我读了此answer,但我仍然感到困惑。
您如何解释impl B for dyn A {}
?
trait A {
fn method_a(&self) {
println!("a");
}
}
trait B {
fn method_b(&self) {
println!("b")
}
}
impl B for dyn A {}
impl A for i32 {}
fn main() {
let x: &dyn A = &10;
x.method_b();
}
我可以理解impl A for i32 {}
,因为i32
是具体类型。 dyn A
不是具体类型(无大小,无法按值传递),您不能声明dyn A
,而只能声明&dyn A
。我应该解释
// x.method_b();
(*x).method_b();
因为*x
是dyn A
?
我也可以声明impl B for &dyn A {}
,为什么我需要impl B for dyn A {}
?用例是什么?
跟进:如果我修改代码
fn main() {
let x: &dyn A = &10;
// have a B trait object over dyn A since
// dyn A implements B
let y: &dyn B = x;
}
它将失败,并抱怨&dyn A
不是&dyn B
。我知道这是一个合理的抱怨,但是我为编译器提供了使用impl B for dyn A {}
的选项。显然,编译器不认为这是一个选项。
您不能声明dyn A
,但是可以声明&dyn A
,因为dyn A
是特征对象type,而&dyn A
是类型T
的实例的pointer实现A
。
历史上,特征可以用作类型和特征。例如,它们都可以工作:
// Where B and A are traits
impl B for A {}
impl B for dyn A {}
[基本上,dyn A
只是A
的糖,以便更清楚地表明它打算用作特征对象类型。
&dyn A
是指向T
类型的实例的指针实例,该实例实现A
和虚拟方法表(vtable),其中包含A
实现的所有方法包。当类型为T
的实例稍后在运行时调用T
的实现时,必须执行此vtable查找。
因此,A
是未调整大小的类型,而dyn A
是具有已知大小的指针。
&dyn A
类型的特质对象必须从指针强制转换为用作实现dyn A
的具体类型。例如,在代码示例中,可以将A
强制转换为i32
:
dyn A
或者可以通过函数强制:
impl B for dyn A {}
impl A for i32 {}
fn main() {
let x: i32 = 10;
(&x as &dyn A).method_a();
(&x as &dyn A).method_b();
}
因为特征是动态大小类型(DST),要将它们用作特征对象,我们必须将它们放在某种指针之后,例如fn dispatch(a: &dyn A) {
a.method_b();
}
或&dyn A
,以便它可以指向可变大小的值并访问vtable调用已实现的方法。
另请参见:Box<dyn A>