如何使用泛型和特征从数组中获取最大的元素?

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

我刚开始学习 Rust,并且在阅读“Rust Book”时正在创造性地尝试一些东西。

我知道可以创建一个通用方法来从数组中获取最大的元素,如下所示:

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

    return largest;
}

并像这样调用 main 函数:

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

除了“扩展”数组之外,我将如何做同样的事情,就像这样:

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

我想最后一个问题是:如果可能的话,这是否是一种不好的做法?为什么?


我试过类似的方法,但没能弄清楚如何实现返回 T 的“Largeble”特性:

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;
    }
}

您需要使 Largeable 特征 return 成为 Vec<T>T,您可以使用关联类型来完成此操作:

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"

Largeable这样的Traits通常被称为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库,它提供了一个在标准库中Iterator添加额外有用方法的trait。

How would I go doing the same thing but "extending" the array

当然,您的代码片段很接近,您可以创建特征并在类型上实现它。

pub trait Largeble<T>
where
    T: Ord,
{
    fn largest(&self) -> Option<&T>;
}

impl<T> Largeble<T> for Vec<T>
where
    T: Ord,
{
    fn largest(&self) -> Option<&T> {
        // Iterator already has a method for getting max which simplifies things
        self.iter().max()
    }
}

或者,您可以将 T 设为 associated type,这可能更适合此示例。

您可以在 Rust Playground 中 运行 此代码。

Would it be a bad practice? Why?

不,这绝对不是坏习惯。这是在 Rust 中开发的一种非常常见的方式,并且非常强大。您的特征需要在范围内才能调用 .largest(),因此它不会污染任何东西。

此外,如果您有多个来自不同特征的同名方法,您可以提供更长的语法来指定您要使用的确切特征:Largest::<u32>::largest(&list).

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

您的代码大部分是正确的,但是您最大的方法没有 return 任何东西。这就是为什么特征需要一个通用的 T 来指定你将 return T.