特徵對象是非常奇怪的野獸。
什麼是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