rusttraitsiterator-traits

Writing rust function with traits working for Vec and array []


I would like to implement a function in rust, computing the norm of an array or Vec

for an Vec<f64> I would write the function as

pub fn vector_norm( vec_a : &Vec<f64> ) -> f64 { 
                                             
    let mut norm = 0 as f64;                     
    for i in 0..vec_a.len(){                     
        norm  +=  vec_a[i] * vec_a[i];     
    }                                  
    norm.sqrt()
}                                             

and for an &[f64] I would do

    pub fn vector_norm( vec_a : &[f64] ) -> f64 { 
                                             
    let mut norm = 0 as f64;                     
    for i in 0..vec_a.len(){                     
        norm  +=  vec_a[i] * vec_a[i];     
    }                                  
    norm.sqrt()
}    

But is there a way to combine both versions into a single function by the use of traits. I was thinking of something like

pub fn vector_norm<T:std::iter::ExactSizeIterator> 
                ( vec_a : &T ) -> f64 {        
                                             
let mut norm = 0 as f64;                       
for i in 0..vec_a.len(){               
    norm  +=  vec_a[i] * vec_a[i]; 
}
norm.sqrt()                               

}

This does not work because the the template parameter T is not indexable. Is it possible to do this somehow?? Maybe with an iterator trait or something?


Solution

  • First of all, Vec<T> implements Deref for [T]. This means that &Vec<f64> can be implicitly converted into &[f64]. So, just taking in a &[f64] will work:

    fn vector_norm(vec_a: &[f64]) -> f64 {
        let mut norm = 0 as f64;
        for i in 0..vec_a.len() {
            norm += vec_a[i] * vec_a[i];
        }
        norm.sqrt()
    }
    
    fn main() {
        let my_vec = vec![1.0, 2.0, 3.0];
        // &my_vec is implicitly converted to &[f64]
        println!("{:?}", vector_norm(&my_vec));
    }
    

    However, if you want to broaden the acceptable values even further to all slice-like types, perhaps AsRef may be of use:

    fn vector_norm<T: AsRef<[f64]>>(vec_a: T) -> f64 {
        // use AsRef to get a &[f64]
        let vec_a: &[f64] = vec_a.as_ref();
        let mut norm = 0 as f64;
        for i in 0..vec_a.len() {
            norm += vec_a[i] * vec_a[i];
        }
        norm.sqrt()
    }
    
    fn main() {
        let my_vec = vec![1.0, 2.0, 3.0];
        println!("{:?}", vector_norm(&my_vec));
    }