rust的一个语法糖:trait bound

rust的一个语法糖:trait bound

我们知道rust是没有继承这个机制的,rust的多态是通过trait来实现的。
官方的教程里是这么介绍的

trait 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共享的行为。可以使用 trait bounds 指定泛型是任何拥有特定行为的类型。

从某种程度上来说,trait就是一种可供多种类型调用的方法。那么trait bound到底是什么呢?从字面上来看bound的意思是范围,限定,那么trait bound因该是有限定范围的trait。我们来看一个例子,假如我们需要取一个vector中最大的数字,我们可以实现如下函数:

fn largest_num(list: &[i32]) -> i32 {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

在这个例子中我们取的是最大的数字,但是当我们取的不是数字,而是最大的字符,甚至是字符串,抑或是其他的类型的时候呢?我们能否用泛型来实现一个通用的函数呢?我们把函数稍作修改可以得到

fn largest_item<T>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

然而,当我们尝试编译时,会看到如下错误

error[E0369]: binary operation `>` cannot be applied to type `T`
  --> src/main.rs:17:12
   |
17 |         if item > largest {
   |            ^^^^^^^^^^^^^^
   |
   = note: `T` might need a bound for `std::cmp::PartialOrd`

编译器提示我们T也许需要一个std::cmp::PartialOrd的限定(bound)。这是怎么回事呢?仔细思考一下这段代码,我们使用了>运算符,这个运算符被定义为标准库中 trait std::cmp::PartialOrd的一个默认方法,然而我们并不知道T类型究竟有没有实现PartialOrd,因而我们需要对T进行限定,即

fn largest_item<T: PartialOrd>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

然而仍然有错误

error[E0508]: cannot move out of type `[T]`, a non-copy slice
 --> src/main.rs:2:23
  |
2 |     let mut largest = list[0];
  |                       ^^^^^^^
  |                       |
  |                       cannot move out of here
  |                       help: consider borrowing here: `&list[0]`

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:4:18
  |
4 |     for &item in list.iter() {
  |         -----    ^^^^^^^^^^^ cannot move out of borrowed content
  |         ||
  |         |data moved here
  |         help: consider removing the `&`: `item`
  |
note: move occurs because `item` has type `T`, which does not implement the `Copy` trait
 --> src/main.rs:4:10
  |
4 |     for &item in list.iter() {
  |          ^^^^

error: aborting due to 2 previous errors

可以看到这是由于我们没有限定Copy,导致list[0]的值不一定能移动到largest中,我们给T再添加上Copy限定,这次编译通过了。

fn largest_item<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];

    let result = largest_item(&number_list);
    println!("The largest number is {}", result);

    let char_list = vec!['a', 'b', 'z', 'c'];

    let result = largest_item(&char_list);
    println!("The largest char is {}", result);

    let str_list = vec!["aaa", "abc", "sss"];
    let result = largest_item(&str_list);
    println!("The largest str is {}", result);

}

得到输出结果

The largest number is 100
The largest char is z
The largest str is sss

当然如果我们希望T中的类型不仅仅是实现了Copy trait的,而是像诸如String类型的值,我们可以修改Copy限定为Clone,当然使用Clone在面对大量数据时效率会降低。

当然,trait bound也有缺点,每个泛型都有自己的trait bound,这会导致有多个泛型的函数声明会变得非常长…例如

fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {

这种时候我们可以用where语法来简化,提高代码的可读性

fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone,
          U: Clone + Debug
{
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值