How to implement `Clone` trait for a struct with `Box<dyn A>` field

I have a struct C, which has a field n of type Box<trait object>:

trait A {}

#[derive(Clone)]
struct B {}

impl A for B {}

struct C {
    n: Box<dyn A>
}

How can I implement the Clone trait on C so that I can do this:

let b: Box<dyn A> = Box::new(B);
let c = C { n: b };

let c_clone = c.clone();

I tried this, but does not work:

impl Clone for Box<dyn A + Clone> {
    fn clone(&self) -> Box<dyn A> {
        Box::new(self.clone())
    }
}
impl Clone for C {
    fn clone(&self) -> Self {
        C { n: self.n.clone()}
    }
}

It’s generally impossible to clone (owned) trait objects using the Clone trait directly. However, it might be possible for you to add a custom method fn foo(&self) -> Box<dyn A> to the A trait that implementors are supposed to implement using cloning. In fact, this can be further aided with a supertrait and a blanket impl… let me show some code:

// new “helper” super trait
trait CloneAsA {
    fn clone_as_a(&self) -> Box<dyn A>;
}
// with a blanket impl:
impl<T: A + Clone> CloneAsA for T {
    fn clone_as_a(&self) -> Box<dyn A> {
        Box::new(self.clone())
    }
}

trait A: CloneAsA + 'static {}

#[derive(Clone)]
struct B {}

impl A for B {}

struct C {
    n: Box<dyn A>
}

impl Clone for C {
    fn clone(&self) -> Self {
        Self {
            n: self.n.clone_as_a(),
        }
    }
}

Note how the blanket impl and super trait together make it possible that implementors no longer have to provide the clone_as_a method manually.


Further alternatives include using the dyn-clone trait (here’s some example code)…

…or perhaps you might want shared-ownership trait objects (like Arc<dyn A>) after all, in which case cloning would become trivial.

5 Likes