[英]What does `impl TraitX for TraitY` mean in Rust?
例如:
trait TraitX { }
trait TraitY { }
impl TraitX for TraitY { }
我认为这意味着同样的
impl<A: TraitY> TraitX for A { }
但错误消息暗示:
$ rustc --version
rustc 0.12.0-nightly (a70a0374e 2014-10-01 21:27:19 +0000)
$ rustc test.rs
test.rs:3:17: 3:23 error: explicit lifetime bound required
test.rs:3 impl TraitX for TraitY { }
^~~~~~
是否impl TraitX for TraitY
(或具有明确生命周期的某些变体)对Rust有什么意义? 如果是这样,它的用途是什么?
impl TraitX for TraitY
使用TraitY
作为动态大小的类型(DST) 。 如果我们添加所需的生命周期绑定(例如,有关生命周期绑定的必要性的更多信息,请参阅此内容),编译器将以这种方式进行抱怨:
trait TraitX { }
trait TraitY { }
impl<'a> TraitX for TraitY+'a { }
fn main() {}
<anon>:3:1: 3:34 error: the trait `core::kinds::Sized` is not implemented for the type `TraitY+'a`
<anon>:3 impl<'a> TraitX for TraitY+'a { }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:3:1: 3:34 note: the trait `core::kinds::Sized` must be implemented because it is required by `TraitX`
<anon>:3 impl<'a> TraitX for TraitY+'a { }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
错误是说TraitY+'a
的大小没有,也就是说,它在编译时没有已知的大小(例如, u8
大小为1, Vec<T>
是3个指针的大小)。
语法是为TraitY
特征对象实现TraitX
(这些在参考的“对象类型”部分中介绍),允许在需要实现TraitX
的值的地方处理它(在指针后面)。 工作用途涉及一些额外的Sized?
注释,这些说它们附加的任何东西都是可选的( ?
)大小(默认是假定大小的东西)。
#![allow(dead_code)]
// indicate that it's OK to implement this trait for DSTs
trait TraitX for Sized? { }
trait TraitY { }
trait TraitZ { }
impl<'a> TraitX for TraitY+'a { }
// the Sized? is to allow DSTs to be passed to this.
fn example<Sized? T: TraitX>(_: &T) {}
fn call_it(x: &TraitY, _y: &TraitZ) {
example::<TraitY>(x); // only possible if `TraitY` impls `TraitX`.
// error:
// example::<TraitZ>(_y); // `TraitZ` doesn't impl `TraitX`.
}
fn main() {}
当前调用具有::<TraitY>
类型的函数时,需要显式的::<TraitY>
类型提示,但这是一个错误#17178 。 目前, DST还存在相当多的漏洞,因此实际使用起来并不容易,但这会有所改善。
DST的主要动机是使处理特征对象与其他指针类型更加一致,例如我们目前仅支持&Trait
和Box<Trait>
特征对象,但DST旨在允许其他指针类型,如Rc<Trait>
, Arc<Trait>
。 DST还允许处理那些像真正的指针,例如,如果obj: Box<Trait>
然后&*obj
现在只能用DST,之前它是非法的,因为trait对象是胖指针,而不是普通指针。
自问这个问题以来,Rust已经发生了很大的变化。 虽然目前仍支持该语法,但现在应使用关键字dyn
指定trait对象:
trait TraitX { }
trait TraitY { }
impl TraitX for dyn TraitY { }
这是完全等同于问题的代码,但更多的是有点明显意味着什么:实施TraitX
为特质对象 dyn TraitY
。
例如:
struct Thing;
impl TraitY for Thing {}
fn main() {
// Treat the &Thing as a dynamic object
let object: &dyn TraitY = &Thing;
// The TraitY object can still be used where a TraitX is expected
do_something(object);
}
fn do_something<T: TraitX + ?Sized>(t: &T) {
}
从表面上看,正如您所提到的,它似乎类似于:
impl<A: TraitY> TraitX for A { }
这实现TraitX
为实现任何具体类型TraitY
,但不包括性状的对象,因为Sized
始终是类型参数的隐式绑定。 但我们可以通过明确选择退出Sized
边界来消除该限制:
impl<A: TraitY + ?Sized> TraitX for A { }
这包括实现TraitY
所有具体类型,但现在还包括动态TraitY
对象。 为了获得最大的灵活性,您应该使用此表单而不是上述任一替代方案。
* “当前”,因为Rust的未来版本可能在这些情况下需要关键字。 至少, 默认的linter将不允许省略它 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.