What is the common strategy for defining a trait on a collection of user-defined types in Rust? By collection, I mean things like a vector or list of user-defined types. As an example, the following code defines two simple structures with some data inside. A common operation is to extract this data and I'd like the ability to also extract this data from a vector containing the type as well:
// External libraries
use std::collections::LinkedList;
use std::iter::IntoIterator;
// Create a struct that contains some data
struct MyStructFoo<T> {
val: T,
}
struct MyStructBar<T> {
other: T,
}
// Setup a trait that exposes values
trait MyTrait<T> {
fn value(self) -> T;
}
impl<T> MyTrait<T> for MyStructFoo<T> {
fn value(self) -> T {
self.val
}
}
impl<T> MyTrait<T> for MyStructBar<T> {
fn value(self) -> T {
self.other
}
}
// Setup a trait for a collection of structs
trait MyCollectionTrait<'a, T> {
fn values(self) -> Box<dyn Iterator<Item = T> + 'a>;
}
impl<'a, Collection, MyStruct, T> MyCollectionTrait<'a, T> for Collection
where
Collection: IntoIterator<Item = MyStruct> + 'a,
MyStruct: MyTrait<T>,
{
fn values(self) -> Box<dyn Iterator<Item = T> + 'a> {
Box::new(self.into_iter().map(|x| x.value()).into_iter())
}
}
fn main() {
// Create some structs
let foo = MyStructFoo { val: 23_u32 };
let bar = MyStructBar { other: 1.2_f32 };
// Print out the values
println!("foo : {} , bar : {}", foo.value(), bar.value());
// Create a vector of some structs
let foos = vec![
MyStructFoo { val: 12_u32 },
MyStructFoo { val: 34_u32 },
MyStructFoo { val: 56_u32 },
];
let mut bars = LinkedList::new();
bars.push_back(MyStructBar { other: 12.3_f32 });
bars.push_back(MyStructBar { other: 45.6_f32 });
bars.push_back(MyStructBar { other: 78.9_f32 });
println!(
"foos : {:?} , bars : {:?}",
{
let v: LinkedList<_> = foos.values().collect();
v
},
{
let v: Vec<_> = bars.values().collect();
v
}
);
}
This produces the expected output:
foo : 23 , bar : 1.2
foos : [12, 34, 56] , bars : [12.3, 45.6, 78.9]
At the same time, it feels kind of heavy in the definition of MyCollectionTrait
. Since the function is inside of a trait, it didn't appear as though we can take advantage of returning an unboxed trait object, impl IntoIterator
. In addition, I needed to play some games with specifying the appropriate lifetime of the arguments and return. Is there a simpler or more efficient way to accomplish a similar kind of code?