Strategies for defining traits on a collection of user-defined types in Rust?

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?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.