以下代码中,无法从实现相同trait的动态大小类型的引用中获取trait对象的引用。为什么会这样?如果我可以使用
实现
取消注释
&dyn Trait
和&(?Sized + Trait)
来调用Trait方法,那么它们之间的区别是什么?实现
FooTraitContainerTrait
的类型可能具有例如type Contained = dyn FooTrait
或type Contained = T
的形式,其中T
是实现FooTrait
的具体类型。在这两种情况下,都很容易获得&dyn FooTrait
。我想不出还有哪种情况行不通。为什么在FooTraitContainerTrait
的通用情况下,这种方法不可行?trait FooTrait {
fn foo(&self) -> f64;
}
///
trait FooTraitContainerTrait {
type Contained: ?Sized + FooTrait;
fn get_ref(&self) -> &Self::Contained;
}
///
fn foo_dyn(dyn_some_foo: &dyn FooTrait) -> f64 {
dyn_some_foo.foo()
}
fn foo_generic<T: ?Sized + FooTrait>(some_foo: &T) -> f64 {
some_foo.foo()
}
///
fn foo_on_container<C: FooTraitContainerTrait>(containing_a_foo: &C) -> f64 {
let some_foo = containing_a_foo.get_ref();
// Following line doesn't work:
//foo_dyn(some_foo)
// Following line works:
//some_foo.foo()
// As does this:
foo_generic(some_foo)
}
取消注释
foo_dyn(some_foo)
后编译器会报错。error[E0277]: the size for values of type `<C as FooTraitContainerTrait>::Contained` cannot be known at compilation time
--> src/main.rs:27:22
|
27 | foo_dyn(contained)
| ^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `<C as FooTraitContainerTrait>::Contained`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= help: consider adding a `where <C as FooTraitContainerTrait>::Contained: std::marker::Sized` bound
= note: required for the cast to the object type `dyn FooTrait`
&dyn Trait
是一个带有额外动态分发信息的胖指针。而你的some_foo
只是一个普通的引用(指针)。类型的大小可以说明这个问题:Playground。 - turbulencetoosome_foo
已经拥有足够的信息来创建一个 trait 对象。如果它是 unsized 类型,那么它就是一个 fat pointer,并且已经包含了所需的 vtable 指针。如果它是 sized 类型,那么强制类型转换可以计算出 vtable 指针,因为在单态化期间它知道具体的类型,对吧? - w1th0utnam3