繁体   English   中英

什么“TraitX for TraitY”在Rust中意味着什么?

[英]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的主要动机是使处理特征对象与其他指针类型更加一致,例如我们目前仅支持&TraitBox<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM