例如:
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中的任何内容?如果是这样,它的用例是什么?
答案 0 :(得分:4)
impl TraitX for TraitY
正在使用TraitY
作为a dynamically sized type (DST)。如果我们添加所需的生命周期限制(请参阅例如this以获取有关生命周期限制的必要性的更多信息),编译器将以这种方式进行抱怨:
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>
是大小三分球)。
语法正在为TraitX
特征对象实现TraitY
(这些在参考的"object types" section中有所涉及),允许对其进行处理(后面)一个指针)在预期值为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() {}
现在调用具有unsized类型的函数时,需要显式::<TraitY>
类型提示,但这是一个错误#17178。目前,仍有quite a few bugs with DST因此在实践中使用起来并不容易,但这会有所改善。
DST的主要动机是使处理特征对象与其他指针类型更加一致,例如:我们目前仅支持&Trait
和Box<Trait>
特征对象,但DST旨在允许其他指针类型,如Rc<Trait>
,Arc<Trait>
。 DST还允许将那些像真正的指针一样处理,例如如果obj: Box<Trait>
那么&*obj
现在只能使用DST,之前它是非法的,因为特征对象是胖指针,而不是普通指针。
答案 1 :(得分:3)
自从提出这个问题以来,铁锈已经发生了很大变化。虽然目前仍支持该语法*,但现在应该使用关键字# assume built-in pthreads on MacOS
IF(APPLE)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
set(THREADS_PREFER_PTHREAD_FLAG ON)
ENDIF()
指定trait对象:
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 { }
的任何 concrete 类型实现TraitX
,但 not 不会包含特征对象,因为TraitY
始终类型参数的隐式绑定。但是我们可以通过显式退出Sized
边界来消除该限制:
Sized
这包括实现impl<A: TraitY + ?Sized> TraitX for A { }
的所有具体类型,但现在 也包括动态TraitY
对象。为了获得最大的灵活性,您应该使用这种形式,而不是上面的任何一种选择。
* “当前”,因为在这种情况下,Rust的未来版本可能会要求使用关键字。至少the default linter will disallow omitting it。