我最近看到使用dyn
关键字的代码:
fn foo(arg: &dyn Display) {}
fn bar() -> Box<dyn Display> {}
这种语法是什么意思?
答案 0 :(得分:21)
TL; DR:用于指定特征对象的类型的语法,出于清晰的原因应该是首选。
自Rust 1.0以来,特质已经过了双重生活。一旦声明了特征,它就可以用作特征或类型:
// As a trait
impl MyTrait for SomeType {}
// As a type!
impl MyTrait {}
impl AnotherTrait for MyTrait {}
你可以想象,这种双重含义会引起一些混乱。此外,由于MyTrait
类型是未分级/动态大小的类型,因此可能会使人们看到非常复杂的错误消息。
为了改善此问题,RFC 2113引入了dyn
语法。从Rust 1.27开始提供此语法:
use std::{fmt::Display, sync::Arc};
fn main() {
let display_ref: &dyn Display = &42;
let display_box: Box<dyn Display> = Box::new(42);
let display_arc: Arc<dyn Display> = Arc::new(42);
}
这个新关键字与impl Trait
语法相似,并努力使trait object的类型明显区别于&#34;裸&#34;特质语法。
可能在随后的edition of Rust中,不推荐使用裸语法,然后最终删除。
答案 1 :(得分:0)
dyn
关键字用于指示类型是特征对象。根据{{3}}:
trait 对象是另一种类型的不透明值,它实现了 一组特征。
换句话说,我们在编译时并不知道对象的具体类型,我们只知道对象实现了 trait。
因为 trait 对象的大小在编译时是未知的,所以它们必须放在指针后面。例如,如果 Trait
是您的特征名称,那么您可以按以下方式使用特征对象:
Box<dyn Trait>
&dyn Trait
保存 trait 对象的变量/参数是胖指针,由以下组件组成:
有关详细信息,请参阅我在 the Rust docs 上的回答。
答案 2 :(得分:0)
我发现这篇博文非常清楚地解释了这个功能:https://medium.com/digitalfrontiers/rust-dynamic-dispatching-deep-dive-236a5896e49b
相关摘录:
struct Service<T:Backend>{
backend: Vec<T> // Either Vec<TypeA> or Vec<TypeB>, not both
}
...
let mut backends = Vec::new();
backends.push(TypeA);
backends.push(TypeB); // <---- Type error here
对比
struct Service{
backends: Vec<Box<dyn Backend>>
}
...
let mut backends = Vec::new();
backends.push( Box::new(PositiveBackend{}) as Box<dyn Backend>);
backends.push( Box::new(NegativeBackend{}) as Box<dyn Backend>);