2014-11-22 4 views
1

У меня проблема с литьем вектора признаков в вектор с разными чертами.Rust Vector of Traits: cast каждая черта

Используя подход Type-casting arrays/vectors in Rust, я в основном пытался следующее:

trait ParentTrait {} 

trait ChildTrait: ParentTrait {} 

fn main() { 
    let mut children: Vec<Box<ChildTrait>> = vec![]; 
    let parents = children.iter().map(|&e| e as Box<ParentTrait>); 
} 

Теперь это не компилируется, это приводит к

error: the trait `core::kinds::Sized` is not implemented for the type `ChildTrait` 
[...] 
error: the trait `ParentTrait` is not implemented for the type `ChildTrait` 
[...] 

(Второй errorline глючит поведение компилятора, Я думаю?)

Я пробовал различные другие варианты ссылок/ящиков и не мог заставить его работать.

Что я делаю неправильно здесь, Это даже правильный подход с более новыми версиями ржавчины (0.13)?

ответ

1

Объекты с изображением - очень странные звери.

Что такое 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? {} 

Тогда мы можем предоставить impl из ParentTrait для типа ChildTrait объекта:

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 успешно скомпилировать или нет.

+0

Благодарим вас за разъяснение! Вы знаете, если это ошибка, которая уже известна? Else Я бы представил новый отчет об ошибках. – LinuCC

+0

Подтверждено, что в настоящее время невозможно отличить черты таким образом, но должно появиться в будущем. – LinuCC