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.
- 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 B
s; 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 Box
s 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() {}