抱歉,如果这看起来微不足道,但我正在尝试做一个简单的操作,但我很难做到。我只想有两个特征对象,其中一个有一个 Vector,其中包含一堆其他对象。
trait MetaClass {
fn new() -> Self;
fn add(&self, subtrait: Box<SubClass>);
}
struct MetaStruct {
elems: Vec<Box<SubClass>>,
}
impl MetaClass for MetaStruct{
fn new() -> MetaStruct {
MetaStruct{
elems: Vec::new(),
}
}
fn add(&self, subtrait: Box<SubClass>){
// if I reformulate the above to 'fn add(&self, subtrait: SubClass){'
// and use the below I get the trait `core::marker::Sized` is not implemented for the type `SubClass`
//self.elems.push(Box::new(subtrait));
self.elems.push(subtrait);
}
}
trait SubClass{
fn new() -> Self;
}
struct MySubClass {
data: i32,
}
impl SubClass for MySubClass {
fn new() -> MySubClass{
MySubClass{
data: 10,
}
}
}
fn main(){
let mut meta = Box::new(MetaStruct::new());
// ideally I just want to do meta.add(MySubClass::new()) but as mentioned above that has some sizing issues :'(
meta.add(Box::new(MySubClass::new()));
}
我得到的错误是:
<anon>:45:11: 45:38 error: cannot convert to a trait object because trait `SubClass` is not object-safe [E0038]
<anon>:45 meta.add(Box::new(MySubClass::new()));
^~~~~~~~~~~~~~~~~~~~~~~~~~~
这是 Rust 游戏的链接:http://is.gd/pjLheJ
我也试过下面的,但得到了同样的错误:
meta.add(Box::new(MySubClass::new()) as Box<SubClass>);
理想情况下,如果有一种方法可以使用 Rust 的静态调度来执行此操作,那将是理想的,但我也可以使用动态调度。在每种情况下,我认为让 MetaClass 实际上拥有子类的对象是有意义的,所以我不想传递对它的引用,而是传递整个对象本身。
最佳答案
I just want to have two trait objects whereby one has a Vector that contains a bunch of the other object.
这很简单:
trait TraitOne {
fn add(&mut self, another: Box<TraitTwo>);
}
trait TraitTwo {
fn value(&self) -> u8;
}
struct Container(Vec<Box<TraitTwo>>);
impl TraitOne for Container {
fn add(&mut self, another: Box<TraitTwo>) {
self.0.push(another);
}
}
struct ThingOne(u8);
impl TraitTwo for ThingOne {
fn value(&self) -> u8 { self.0 }
}
struct ThingTwo(u8, u8);
impl TraitTwo for ThingTwo {
fn value(&self) -> u8 { self.0 + self.1 }
}
fn main() {
let mut trait_1: Box<TraitOne> = Box::new(Container(vec![]));
let thing_1: Box<TraitTwo> = Box::new(ThingOne(42));
let thing_2: Box<TraitTwo> = Box::new(ThingTwo(21, 21));
trait_1.add(thing_1);
trait_1.add(thing_2);
}
您真正的错误在于对象安全。 Huon Wilson(Rust 核心团队成员)写了一个 great blog post about this .
在你的情况下你有这个特征:
trait SubClass{
fn new() -> Self;
}
这不是对象安全的,引用 Huon(强调我的):
There’s two fundamental ways in which this can happen, as an argument or as a return value, in either case a reference to the Self type means that it must match the type of the self value, the true type of which is unknown at compile time.
也就是说,需要在栈或堆上分配多少字节来存放fn new() -> Self
返回的对象?你无法知道,因为你只有一个特征对象。
一种解决方案是根据 followup blog post 确保 Self
在您的特征中是 Sized
:
trait SubClass {
fn new() -> Self where Self: Sized;
}
然后,只需修复特征中的一些可变性不匹配,它就会编译。
关于rust - 在基本特征对象中包含特征对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31592339/