铁锈矢量的性状:铸造每个性状 [英] Rust Vector of Traits: cast each trait
问题描述
我有一个问题,将一个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)的正确方法吗?
什么是
? 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屋!