Returning trait from a trait?

I have a Vec<Box<Parent>>. The P struct implements Parent and has a data field that is a generic that implements Child. Is there any way to return the data from the Parent trait?

trait Child: Clone {
    type Msg;
}

trait Parent {
    // fn get_child(&self) -> ?;
}

struct P<T> {
    data: T,
}

impl<T: Child> Parent for P<T> {}

#[derive(Clone)]
struct A;
#[derive(Clone)]
struct B;

impl Child for A {
    type Msg = ();
}
impl Child for B {
    type Msg = ();
}

fn main() {
    let p: Vec<Box<Parent>> = vec![Box::new(P { data: A {} }), Box::new(P { data: B {} })];
}
1 Like
trait Parent {
    type Child;
    fn get_child(&self) -> Self::Child;
}

fn main() {
    let p: Vec<Box<dyn Parent<Child = ()>>> = vec![Box::new(P { data: A {} }), Box::new(P { data: B {} })];
}
1 Like

You need to either fully specify things (like @RustyYato's answer), or make everything dyn all the way down.

If you take the second option, that basically means returning a dyn Child<Msg=()>, or further making removing the Msg type from Child (and doing the same thing you're doing with the Parent->Child relationship). I don't know what's best for your use case. Just know that for any type, the rust compiler needs to know the full details of how it behaves. For dyn Trait, that just means

Using dyn Child, you'll run into another problem, though: that dyn Trait can't exist when Trait: Clone. This is because clone's signature is clone(&self) -> Self, so it needs to know what Self is in order to return it.

To work around that, a common pattern is to add a boxed_clone(&self) -> Box<dyn Trait> method, and to potentially implement it by default. This thread has many more details on that: Why can't traits require Clone? - #17 by BatmanAoD.

A less boilerplate-heavy alternative is to depend on a crate like dyn-clone. This would allow a simple bound change from Child: Clone to Child: dyn_clone::DynClone & some macro usage from that crate.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.