1

此代码工作正常(操场):

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 编译器的反应不同?

4

1 回答 1

2

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

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

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

解决方法是选择退出Sizedtrait T

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

并且在实现的上下文中:

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

?Sized其实不是约束,而是放宽已有的Sized约束,这样就不需要了。

选择退出的结果Sized是该块中的任何Bar' 方法impl都不能使用T,除非通过引用。

于 2019-03-08T14:40:36.003 回答