我阅读了这个答案,但我仍然感到困惑。
你怎么解释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();
}
Run Code Online (Sandbox Code Playgroud)
我可以理解,impl A for i32 {}因为i32是具体类型。dyn A不是具体类型(未调整大小,不能按值传递),并且您不能声明 adyn A但只能声明 a &dyn A。我应该解释吗
// x.method_b();
(*x).method_b();
Run Code Online (Sandbox Code Playgroud)
因为*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;
}
Run Code Online (Sandbox Code Playgroud)
它会失败,抱怨&dyn A不会&dyn B。我知道这是一个合理的抱怨,但我为编译器提供了使用impl B for dyn A {}. 显然,编译器不认为这是一个选项。
您无法声明,dyn A但可以声明,&dyn A因为dyn A是 特征对象类型,而&dyn A是指向实现 的类型实例的指针。TA
从历史上看,特征可以用作类型和特征。例如,这两者都有效:
\n\n// Where B and A are traits\nimpl B for A {}\nimpl B for dyn A {}\nRun Code Online (Sandbox Code Playgroud)\n\n基本上,dyn A只是一个糖衣,A以使其更清楚地表明它旨在用作特征对象类型。您不会为另一个特征实现一个特征。您为另一个特征对象类型实现一个特征。
&dyn AT是一个指向实现的类型实例的指针实例和一个虚拟方法表(vtable),其中包含该实现A的方法的所有包袱。当类型的实例稍后在运行时调用 \ 的实现时,此 vtable 查找是必要的。ATTA
因此,dyn A是一个未确定大小的类型,而&dyn A是一个已知大小的指针。
类型的 Trait 对象dyn A必须从指针进行转换才能用作实现A. 例如,在代码示例中,i32可以转换为dyn A:
impl B for dyn A {}\n\nimpl A for i32 {}\n\nfn main() {\n let x: i32 = 10;\n (&x as &dyn A).method_a(); \n (&x as &dyn A).method_b();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n或者它可以被函数强制:
\n\nfn dispatch(a: &dyn A) {\n a.method_b();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n因为特征是动态大小的类型(DST),所以要将它们用作特征对象,我们必须将它们放在某种指针后面,例如&dyn A它Box<dyn A>可以指向可变大小的值并访问 vtable 来调用已实现的方法。
另请参阅:什么使某物成为 \xe2\x80\x9ctrait 对象\xe2\x80\x9d?
\n| 归档时间: |
|
| 查看次数: |
934 次 |
| 最近记录: |