铁锈矢量的性状:铸造每个性状 [英] Rust Vector of Traits: cast each trait

查看:174
本文介绍了铁锈矢量的性状:铸造每个性状的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,将一个traits的向量投射到不同traits的向量中。



使用类型转换数组/向量在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>);
}

现在这个不编译,结果是

 错误:trait`core :: kinds :: Sized`没有实现类型`ChildTrait` 
[...]
error:the trait`ParentTrait`没有实现类型`ChildTrait`
[...]

(第二个错误是编译器的错误行为,我猜?)



我尝试了其他种类的引用/



我在这里做错了什么,
是更新版本的rust(0.13)的正确方法吗?

$ b



什么是

Box< T> 字面上是 * mut T 的包装器。因此, Box< ChildTrait> 包装一个 * mut ChildTrait 。因为 ChildTrait 命名一个trait, ChildTrait 是一个 对象类型 。指向对象类型的指针由一对指针表示:指向该trait的vtable的指针和只有该trait ,以及指向实际值的指针。



当我们从另一个trait继承一个trait时,这并不意味着我们可以从指向第二个trait的vtable的指针获得指向第一个trait的vtable的指针。这是为什么编译器抱怨

 特性`ParentTrait`没有实现类型`ChildTrait` 

但是,我们可以手动实现对象类型的trait。因为对象类型未定义,我们必须首先允许为未定义的类型实现 ParentTrait

  trait ParentTrait for Sized? {} 

然后我们可以提供 impl ChildTrait 对象类型



<$ p $

impl<'a> ParentTrait for ChildTrait +'a {}



如果我们现在尝试编译,会得到不同的错误: p>

 < anon>:9:40:9:42错误:无法移出`&`-pointer 
< anon>:9 let parents = children.iter()。map(|& e | e as Box< ParentTrait>);
^〜
< anon>:9:41:9:42注意:尝试将值移动到这里
< anon>:9 let parents = children.iter (|& e | e as Box< ParentTrait>);
^
< anon>:9:41:9:42 help:为了防止移动,使用`ref e`或`ref mut e`通过引用捕获值
< anon>:9 let parents = children.iter()。map(|& e | e as Box< ParentTrait>);

我们可以使用 into_iter c $ c> iter 以使用初始 Vec

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

但是我们得到一个内部编译器错误:

 错误:内部编译器错误:试图获取ChildTrait的大小类型,未定义类型
注意:编译器意外惊慌。这是一个错误。
注意:我们会感谢一个错误报告:http://doc.rust-lang.org/complement-bugreport.html
注意:使用`RUST_BACKTRACE = 1`运行回溯
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后,这将成功编译或不成功。


I have a problem casting a vector of traits into a vector of different traits.

Using the approach of Type-casting arrays/vectors in Rust , I basically tried the following:

trait ParentTrait {}

trait ChildTrait: ParentTrait {}

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

Now this does not compile, it results in

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

(The second errorline is buggy behaviour of the compiler, I guess?)

I tried various other flavors of References / Boxes and could not get it to work.

What am I doing wrong here, is this even the correct approach with newer versions of rust (0.13)?

解决方案

Trait objects are very strange beasts.

What is a Box<ChildTrait>? Box<T> is literally a wrapper for a *mut T. Therefore, a Box<ChildTrait> wraps a *mut ChildTrait. Because ChildTrait names a trait, ChildTrait is an object type. A pointer to an object type is represented by a pair of pointers: a pointer to the vtable for that trait and only that trait, and a pointer to the actual value.

When we inherit a trait from another trait, that doesn't mean we can obtain a pointer to the vtable for the first trait from a pointer to the vtable for the second trait. This is why the compiler complains that

the trait `ParentTrait` is not implemented for the type `ChildTrait`

We can, however, manually implement a trait for an object type. Because object types are unsized, we must first allow ParentTrait to be implemented for unsized types:

trait ParentTrait for Sized? {}

Then we can provide an impl of ParentTrait for the ChildTrait object type:

impl<'a> ParentTrait for ChildTrait+'a {}

If we try to compile now, we get different errors:

<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>);

We can use into_iter instead of iter to consume the initial Vec:

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

But then we get an internal compiler error:

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

The same error also occurs with this code:

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

At this point, I don't know if, after fixing the ICE, this would compile successfully or not.

这篇关于铁锈矢量的性状:铸造每个性状的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆