为什么生成器函数需要 sized trait 来生成 Rc<T>?

Why sized trait is required for a builder function to generate Rc<T>?

这段代码工作正常(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()
}

但是如果我制作一个包装器来生成如下所示的 Rc,编译器会抱怨缺少大小特征 (playground)

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

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

在这两种情况下,Bar::new 接收到相同类型 Rc 的参数,为什么 rust 编译器的反应不同?

默认情况下,所有类型变量都假定为Sized。例如,在 Bar 结构体的定义中,有一个隐含的 Sized 约束,像这样:

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

对象 dyn Foo 不能Sized 因为 Foo 的每个可能实现可能有不同的大小,所以没有可以选择的一种尺寸。但是您正在尝试实例化 Bar<dyn Foo>.

修复方法是选择退出 TSized 特征:

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

并且在实现的上下文中:

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

?Sized其实不是约束,而是放宽了已有的Sized约束,所以不需要了。

选择退出 Sized 的结果是 impl 块中 Bar 的方法中的 none 可以使用 T,除了参考。