Reputation: 31
I'm new to rust and I experience difficulties to develop my personal first project.
To get the essential my code looks like this:
pub trait MyTrait {
type Out: MyTrait;
fn foo(&self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self <>;
fn foo(&self) -> Box<Self::Out> {
Box::new(self)
}
}
The error message I get is :
expected struct
MyStruct<T>
found reference&MyStruct<T>
I tried many things but I can't find how to return a box to self...
I have another question: actually MyTrait extends another trait and I have many struct that implement MyTrait so in my code I have many impl, one for each trait by struct and I find it really verbose, isn't it possible to implement all methods (from a trait and all its parents) at once (like in java) ? Or is there syntactic sugar to implement methods with closures ?
Thanks
Upvotes: 0
Views: 1069
Reputation: 22456
Box
needs to own self
. You cannot pass a reference into it, it has to be the actual self
object.
This works:
pub trait MyTrait {
type Out: MyTrait;
fn foo(self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self;
fn foo(self) -> Box<Self::Out> {
Box::new(self)
}
}
Further remarks:
I'm unsure why you need that function, but it seems to me like you are trying to downcast from a boxed dyn trait to an actual type.
Sadly, this won't work this way. It's impossible for the compiler to figure out which type was the original type if your Box<dyn MyTrait>
doesn't contain that information any more. That's why you need the Out
associated type here, but you probably didn't yet realize that this means you can no longer store a Box<dyn MyTrait>
object. It's now a Box<dyn MyTrait<Out = MyStruct>>
object, which cannot be mixed with other MyTrait
types any more.
If you really want to achieve that, there are several options. RTTI is one option, with the Any
trait.
Another one would be a Visitor pattern, which could resolve this:
pub trait Visitor {
fn visit_mystruct(&mut self, s: &mut MyStruct);
}
pub struct MyVisitor;
impl Visitor for MyVisitor {
fn visit_mystruct(&mut self, s: &mut MyStruct) {
println!("Visited MyStruct: {:?}", s.0);
}
}
pub trait MyTrait {
fn visit(&mut self, visitor: &mut dyn Visitor);
}
pub struct MyStruct(i32);
impl MyTrait for MyStruct {
fn visit(&mut self, visitor: &mut dyn Visitor) {
visitor.visit_mystruct(self);
}
}
fn main() {
let mut obj: Box<dyn MyTrait> = Box::new(MyStruct(42)) as Box<dyn MyTrait>;
let mut visitor = MyVisitor;
// Here is no information any more about the actual type of `obj`.
// Visitor gets the type resolved again
obj.visit(&mut visitor);
}
Visited MyStruct: 42
A visitor pattern is especially useful in cases like tree structures, because it can be recursively applied to children. It is commonly used in compilers.
Another alternative would be to use an Enum
instead of a Box<dyn Trait>
.
Although those are all just based on assumptions now.
Upvotes: 4