- The first step is to create a
ToAny
trait that will be implemented for all our structures.
use std::any::Any;
pub trait ToAny {
fn as_any(&self) -> &dyn Any;
}
trait Foo: ToAny {}
It requires implementing the ToAny
trait to force each structure implementing Foo
to implement ToAny
too.
- Let's create our structures:
struct A {
id: i32,
}
impl ToAny for A {
fn as_any(&self) -> &dyn Any {
self
}
}
impl Foo for A {}
struct B {
id: i32,
}
impl ToAny for B {
fn as_any(&self) -> &dyn Any {
self
}
}
impl Foo for B {}
The implementation of ToAny
is always the same, we could create a macro implementing it easily.
- And then, we can create a
Vec
instead of a tuple to store our values:
let boxeds: Vec<Box<dyn A>> = vec![
Box::new(A {id: 1}),
Box::new(B {id: 2}),
Box::new(A {id: 3}),
Box::new(B {id: 4}),
];
// Stores the values being `B`.
let mut bees: Vec<&B> = vec![];
for boxed in &boxeds {
// `Some(x)` if `boxed` contains a `B` value.
let found = match boxed.as_any().downcast_ref::<B>() {
Some(b) => b,
None => {}, // it is a `A` value.
};
bees.push(found);
}
assert_eq!(bees, vec![
&B {id: 2},
&B {id: 4}
]);
If we refer to the question, the following code:
fn bar<T: Foo>(tuple: (T...)) {
}
can be this valid code:
fn bar(values: Vec<Box<dyn Foo>>) {
}
I've written a gist file being tests for that. Be careful, I've changed the names in this post, Foo
is A
and there is only the B
structure.