特征对象是非常奇怪的野兽。
什么是Box<ChildTrait>
? Box<T>
实际上是*mut T
的包装。因此,Box<ChildTrait>
包装*mut ChildTrait
。因为ChildTrait
命名特征,ChildTrait
是object type。指向对象类型的指针由一对指针表示:指向该特征的vtable的指针,并且仅指示特征和指向实际值的指针。
当我们从另一个特征继承特征时,这并不意味着我们可以从指向第二特征的vtable的指针获得指向第一特征的vtable的指针。这就是为什么编译器会抱怨
the trait `ParentTrait` is not implemented for the type `ChildTrait`
但是,我们可以手动实现对象类型的特征。由于对象类型未施胶,首先要允许ParentTrait
为未分级的类型来实现:
trait ParentTrait for Sized? {}
然后,我们可以为ChildTrait
对象类型提供的ParentTrait
的impl
:
impl<'a> ParentTrait for ChildTrait+'a {}
如果我们尝试现在编译,我们得到不同的错误:
<anon>:9:40: 9:42 error: cannot move out of dereference of `&`-pointer
<anon>:9 let parents = children.iter().map(|&e| e as Box<ParentTrait>);
^~
<anon>:9:41: 9:42 note: attempting to move value to here
<anon>:9 let parents = children.iter().map(|&e| e as Box<ParentTrait>);
^
<anon>:9:41: 9:42 help: to prevent the move, use `ref e` or `ref mut e` to capture value by reference
<anon>:9 let parents = children.iter().map(|&e| e as Box<ParentTrait>);
我们可以用into_iter
代替iter
消耗初始Vec
:
fn main() {
let mut children: Vec<Box<ChildTrait>> = vec![];
let parents = children.into_iter().map(|e| e as Box<ParentTrait>);
}
但后来我们得到了一个内部编译器错误:
error: internal compiler error: trying to take the sizing type of ChildTrait, an unsized type
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' panicked at 'Box<Any>', /build/rust-git/src/rust/src/libsyntax/diagnostic.rs:175
同样的错误也与此代码出现:
fn main() {
let mut children: Vec<Box<ChildTrait>> = vec![];
let parents = children.iter().map(|e| &**e as &ParentTrait);
}
在这一点上,我不知道在修复ICE之后,它是否会成功编译。
谢谢你的解释!你知道这是一个已知的错误吗?否则我会提交一个新的bug报告。 – LinuCC 2014-11-22 15:05:04
证实目前不可能通过这种方式施加特征,但应该在将来进行。 – LinuCC 2014-11-23 18:06:11