此代码可以正常工作(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编译器的反应不同?
答案 0 :(得分:2)
默认情况下,所有类型变量都假定为Sized
。例如,在Bar
结构的定义中,存在一个隐式Sized
约束,如下所示:
struct Bar<T: Sized> {
v: Rc<T>,
}
对象dyn Foo
不能为Sized
,因为Foo
的每种可能的实现都可以具有不同的大小,因此没有一个大小可以选择。但是您正在尝试实例化Bar<dyn Foo>
。
解决方法是针对Sized
选择退出T
特性:
struct Bar<T: ?Sized> {
v: Rc<T>,
}
以及在实现的上下文中:
impl<T: ?Sized> Bar<T>
where
T: Foo
?Sized
实际上不是约束,而是放宽现有的Sized
约束,因此不是必需的。
选择退出Sized
的后果是,除非引用,否则Bar
块中impl
的方法都不能使用T
。