Home > Net >  Clone Box with generics
Clone Box with generics

Time:09-03

This question is a simpler example of my last question that is still unanswered because is too complex, so following the comments, I removed some generics.

Clone Box<dyn Trait<'a,A>

  • ATrait is a generator that generates BTrait implementors.
  • MultiA is a concatenator of generators.
  • I need to clone generators.

This is the code:

trait BTrait {}

trait ATrait<B: BTrait>: CloneATrait {
    fn do_A(&mut self) -> Vec<B>;
}

trait CloneATrait {
    fn clone_box<B: BTrait>(&self) -> Box<dyn ATrait<B>>;
}

impl<B: BTrait, T> CloneATrait for T
where
    T: 'static   ATrait<B>   Clone,
{
    fn clone_box(&self) -> Box<dyn ATrait<B>> {
        Box::new(self.clone())
    }
}

impl<B: BTrait> Clone for Box<dyn ATrait<B>> {
    fn clone(&self) -> Box<dyn ATrait<B>> {
        self.clone_box()
    }
}

#[derive(Clone)]
struct MultiA<B: BTrait> {
    comps: Vec<Box<dyn ATrait<B>>>,
}

impl<B: BTrait> MultiA<B> {
    fn new(comps: Vec<Box<dyn ATrait<B>>>) -> Self {
        Self { comps }
    }
}

impl<B: BTrait> ATrait<B> for MultiA<B> {
    fn do_A(&mut self) -> Vec<B> {
        let mut res: Vec<B> = Vec::new();
        for a in &self.comps {
            res.append(a.do_A());
        }
        res
    }
}

fn main() {}

That gives me the following compiler error:

 Compiling playground v0.0.1 (/playground)
error[E0207]: the type parameter `B` is not constrained by the impl trait, self type, or predicates
  --> src/main.rs:13:6
   |
13 | impl<B : BTrait, T> CloneATrait for T
   |      ^ unconstrained type parameter

For more information about this error, try `rustc --explain E0207`.
error: could not compile `playground` due to previous error

It works fine for a simple generator:

trait BTrait {
  
}

trait ATrait<B : BTrait> {
    fn do_A(&mut self) -> Vec<B>;
}


impl BTrait for usize{
    
}

impl BTrait for f64{
    
}

#[derive(Clone)]
struct SingleA {
}


impl ATrait<usize> for SingleA {
    fn do_A(&mut self)  -> Vec<usize>{
        vec![1,2,3]
    }
}

impl ATrait<f64> for SingleA {
    fn do_A(&mut self)  -> Vec<f64>{
        vec![1.0,2.0,3.0]
    }
}


fn main() {
    let mut t = SingleA{};
    <SingleA as ATrait<usize>>::do_A(&mut t);
    <SingleA as ATrait<f64>>::do_A(&mut t);
}

So my problem is cloning Vec<Box<dyn ATrait<B>>>

CodePudding user response:

You have tried to implement CloneATrait (non-generic) for a ATrait<B> (generic) in a way that doesn't make sense. The reason the compiler complains that B is unconstrained is because T can implement ATrait for any number of Bs; how shall it decide which one to use when implementing CloneATrait?

Judging by the rest of the code, which all is generic over B, CloneATrait should be generic over B as well. Fixing that (which also addresses the signature of clone_box in the trait and implementation mismatch) looks like this:

trait BTrait {}

trait ATrait<B: BTrait>: CloneATrait<B> {
    fn do_A(&mut self) -> Vec<B>;
}

trait CloneATrait<B: BTrait> {
    fn clone_box(&self) -> Box<dyn ATrait<B>>;
}

impl<B: BTrait, T> CloneATrait<B> for T
where
    T: 'static   ATrait<B>   Clone,
{
    fn clone_box(&self) -> Box<dyn ATrait<B>> {
        Box::new(self.clone())
    }
}

impl<B: BTrait> Clone for Box<dyn ATrait<B>> {
    fn clone(&self) -> Box<dyn ATrait<B>> {
        self.clone_box()
    }
}

This reveals a new problem:

error[E0277]: the trait bound `B: Clone` is not satisfied
  --> src/main.rs:37:17
   |
37 | impl<B: BTrait> ATrait<B> for MultiA<B> {
   |                 ^^^^^^^^^ the trait `Clone` is not implemented for `B`
   |
note: required because of the requirements on the impl of `Clone` for `MultiA<B>`
  --> src/main.rs:26:10
   |
26 | #[derive(Clone)]
   |          ^^^^^
... snip ...

You don't actually need B: Clone, but using #[derive(Clone)] will require it anyway. And even if that wasn't a problem, you wouldn't be able to clone Vec<Box<dyn ATrait<B>>> anyway because Boxs don't clone and you haven't indicated it should use your clone_box implementation.

So you need to implement Clone yourself:

impl<B: BTrait> Clone for MultiA<B> {
    fn clone(&self) -> Self {
        Self {
            comps: self.comps.iter().map(|a| a.clone_box()).collect(),
        }
    }
}

Fixing that reveals that you need a 'static bound on B for MultiA<B> to satisfy 'static required by CloneATrait when implementing ATrait. Then you need to use &mut when iterating over self.comps because do_A requires mutation. And then you need to use extend instead of append since you're concatenating a whole other Vec.

The full compiling code looks like this (playground):

trait BTrait {}

trait ATrait<B: BTrait>: CloneATrait<B> {
    fn do_A(&mut self) -> Vec<B>;
}

trait CloneATrait<B: BTrait> {
    fn clone_box(&self) -> Box<dyn ATrait<B>>;
}

impl<B: BTrait, T> CloneATrait<B> for T
where
    T: 'static   ATrait<B>   Clone,
{
    fn clone_box(&self) -> Box<dyn ATrait<B>> {
        Box::new(self.clone())
    }
}

impl<B: BTrait> Clone for Box<dyn ATrait<B>> {
    fn clone(&self) -> Box<dyn ATrait<B>> {
        self.clone_box()
    }
}

struct MultiA<B: BTrait> {
    comps: Vec<Box<dyn ATrait<B>>>,
}

impl<B: BTrait> MultiA<B> {
    fn new(comps: Vec<Box<dyn ATrait<B>>>) -> Self {
        Self { comps }
    }
}

impl<B: BTrait> Clone for MultiA<B> {
    fn clone(&self) -> Self {
        Self {
            comps: self.comps.iter().map(|a| a.clone_box()).collect(),
        }
    }
}

impl<B: BTrait   'static> ATrait<B> for MultiA<B> {
    fn do_A(&mut self) -> Vec<B> {
        let mut res: Vec<B> = Vec::new();
        for a in &mut self.comps {
            res.extend(a.do_A());
        }
        res
    }
}

fn main() {}
  • Related