1

This code works fine (playground):

use std::rc::Rc;

trait Foo {
    fn foo(&self);
}

struct Bar<T> {
    v: Rc<T>,
}

impl<T> Bar<T> where
T: Foo {
    fn new(rhs: Rc<T>) -> Bar<T> {
        Bar{v: rhs}
    }
}

struct Zzz {
}

impl Zzz {
    fn new() -> Zzz {
        Zzz{}
    }
}

impl Foo for Zzz {
    fn foo(&self) {
        println!("Zzz foo");
    }
}

fn make_foo() -> Rc<Foo> {
    Rc::new(Zzz{})
}

fn main() {
    let a = Bar::new(Rc::new(Zzz::new()));
    a.v.as_ref().foo()
}

but if I make a wrapper to generate Rc like below, the compiler complains about missing sized trait (playground)

fn make_foo() -> Rc<dyn Foo> {
    Rc::new(Zzz::new())
}

fn main() {
    let a = Bar::new(make_foo());
    a.v.as_ref().foo()
}

in both cases, Bar::new received parameters with same type Rc, why the rust compiler reacts different?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Eric Wu
  • 15
  • 5
  • 2
    Possible duplicate of [core::marker::Sized not implemented for Foo](https://stackoverflow.com/questions/32446485/coremarkersized-not-implemented-for-foo) – E_net4 Mar 08 '19 at 11:09
  • 1
    Applied to this question: `T` has a `Sized` constraint by default, which should be removed when implementing `new(rhs: Rc)`: `impl Bar where T: Foo { ... }`. – E_net4 Mar 08 '19 at 11:13

1 Answers1

2

By default, all type variables are assumed to be Sized. For example, in the definition of the Bar struct, there is an implicit Sized constraint, like this:

struct Bar<T: Sized> {
    v: Rc<T>,
}

The object dyn Foo cannot be Sized since each possible implementation of Foo could have a different size, so there isn't one size that can be chosen. But you are trying to instantiate a Bar<dyn Foo>.

The fix is to opt out of the Sized trait for T:

struct Bar<T: ?Sized> {
    v: Rc<T>,
}

And also in the context of the implementations:

impl<T: ?Sized> Bar<T>
where 
    T: Foo 

?Sized is actually not a constraint, but relaxing the existing Sized constraint, so that it is not required.

A consequence of opting out of Sized is that none of Bar's methods from that impl block can use T, except by reference.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204