Search code examples
arraysgenericsrusttraits

How can I get the largest element from array, using generics and traits?


I just started learning rust and I'm creatively trying somethings as I read "the Rust Book".

I know it is possible to create a generic method to get the largest element from an array, like the following:

fn largest<T: PartialOrd + Copy> (nums: &[T]) -> T {
    let mut largest = nums[0];
    for &el in nums {
        if el > largest {
            largest = el;
        }
    } 

    return largest;
}

And calling the main function like this:

fn main() {
    let list: Vec<u32> = vec![1,7,4];
    println!("{}", largest(&list)); // 7
}

How would I go doing the same thing but "extending" the array, like this:

fn main() {
    let list: Vec<u32> = vec![1,7,4];
    println!("{}", list.largest()); // 7
}

I guess the final question is: if it is possible, would it be a bad practice? Why?


I tried something like this, but didn't manage to figure out how to implement the "Largeble" trait returning the T:

pub trait Largeble {
    fn largest(&self);
}

impl<T: Copy + PartialOrd + Display> Largeble for Vec<T> {
    fn largest(&self) {
        
        let mut largest = match self.get(0) {
            Some(&el) => el,
            None => panic!("Non Empty array expected")
        };

        for &el in self {
            if el > largest {
                largest = el;
            }
        } 
    
        println!("{}", largest);
        // return largest;
    }
}

Solution

  • You need to make the Largeable trait return a T from the Vec<T>, which you can do with an associated type:

    use std::fmt;
    
    pub trait Largeble {
        type Output;
        fn largest(&self) -> Self::Output;
    }
    
    impl<T: Copy + PartialOrd + fmt::Display> Largeble for Vec<T> {
        type Output = T;
        fn largest(&self) -> T {
            let mut largest = match self.get(0) {
                Some(&el) => el,
                None => panic!("Non Empty array expected")
            };
    
            for &el in self {
                if el > largest {
                    largest = el;
                }
            } 
        
            largest
        }
    }
    
    println!("{}", vec![1, 2, 3, 2].largest()); // prints "3"
    

    Traits like Largeable are usually called extension traits, since they extend existing items with new features. Using extension traits to extend items in existing libraries is common in the Rust ecosystem. It's common to suffix the names of extensions with Ext (so a collection of additional methods for Vec would be called VecExt). A popular use of extension traits is the itertools library, which provides a trait that adds additional useful methods to Iterator in the standard library.