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
{