trait bound 是泛型的「入场券」:告诉编译器 T 至少会什么。这篇用真实报错验证它的几个关键行为:什么时候必须写、不满足时报什么、多个约束与 where 的写法、按约束有条件地提供方法,以及它在机器码层面意味着什么。
源码:
1 | fn largest<T>(list: &[T]) -> &T {
2 | let mut m = &list[0];
3 | for x in list { if x > m { m = x; } }
4 | m
5 | }
6 | fn main() { println!("{}", largest(&[1, 5, 2])); }
编译:失败
error[E0369]: binary operation `>` cannot be applied to type `&T`
--> <实验目录>/src/u37a.rs:3:26
|
3 | for x in list { if x > m { m = x; } }
| - ^ - &T
| |
| &T
|
help: consider restricting type parameter `T` with trait `PartialOrd`
|
1 | fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {
| ++++++++++++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0369`. 源码:
1 | fn largest<T: PartialOrd>(list: &[T]) -> &T {
2 | let mut m = &list[0];
3 | for x in list { if x > m { m = x; } }
4 | m
5 | }
6 | fn main() {
7 | println!("i32:{} f64:{} char:{} &str:{}", largest(&[1, 5, 2]), largest(&[1.5, 0.2]), largest(&['a', 'z', 'm']), largest(&["pear", "apple"]));
8 | println!("String:{}", largest(&[String::from("b"), String::from("a")]));
9 | }
编译:成功
运行(退出码 0):
i32:5 f64:1.5 char:z &str:pear
String:b
源码:
1 | fn largest<T: PartialOrd>(list: &[T]) -> &T { let mut m = &list[0]; for x in list { if x > m { m = x; } } m }
2 | struct P { x: i32 }
3 | fn main() { let v = [P { x: 1 }, P { x: 2 }]; largest(&v); }
编译:失败
error[E0277]: can't compare `P` with `P`
--> <实验目录>/src/u37c.rs:3:55
|
3 | fn main() { let v = [P { x: 1 }, P { x: 2 }]; largest(&v); }
| ------- ^^ no implementation for `P < P` and `P > P`
| |
| required by a bound introduced by this call
|
= help: the trait `PartialOrd` is not implemented for `P`
note: required by a bound in `largest`
--> <实验目录>/src/u37c.rs:1:15
|
1 | fn largest<T: PartialOrd>(list: &[T]) -> &T { let mut m = &list[0]; for x in list { if x > m { m = x; } } m }
| ^^^^^^^^^^ required by this bound in `largest`
help: consider annotating `P` with `#[derive(PartialOrd)]`
|
2 + #[derive(PartialOrd)]
3 | struct P { x: i32 }
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. 源码:
1 | use std::fmt::{Debug, Display};
2 | fn show_both<T: Display + Clone, U: Debug>(t: &T, u: &U) -> String { format!("{} / {:?} / 克隆的 {}", t, u, t.clone()) }
3 | fn show_where<T, U>(t: &T, u: &U) -> String where T: Display + Clone, U: Debug { show_both(t, u) }
4 | fn main() {
5 | println!("{}", show_both(&"hi", &vec![1, 2]));
6 | println!("{}", show_where(&3.5, &Some('x')));
7 | }
编译:成功
运行(退出码 0):
hi / [1, 2] / 克隆的 hi
3.5 / Some('x') / 克隆的 3.5 源码:
1 | use std::fmt::Display;
2 | struct Pair<T> { a: T, b: T }
3 | impl<T> Pair<T> { fn new(a: T, b: T) -> Self { Pair { a, b } } } // 对所有 T 都有
4 | impl<T: Display + PartialOrd> Pair<T> { // 只有 T 满足约束才有
5 | fn show_largest(&self) { if self.a >= self.b { println!("最大的是 a = {}", self.a) } else { println!("最大的是 b = {}", self.b) } }
6 | }
7 | struct NoDisplay;
8 | fn main() {
9 | Pair::new(3, 9).show_largest();
10 | let p = Pair::new(NoDisplay, NoDisplay);
11 | p.show_largest();
12 | }
编译:失败
error[E0599]: the method `show_largest` exists for struct `Pair<NoDisplay>`, but its trait bounds were not satisfied
--> <实验目录>/src/u37e.rs:11:7
|
2 | struct Pair<T> { a: T, b: T }
| -------------- method `show_largest` not found for this struct
...
7 | struct NoDisplay;
| ---------------- doesn't satisfy `NoDisplay: PartialOrd` or `NoDisplay: std::fmt::Display`
...
11 | p.show_largest();
| ^^^^^^^^^^^^ method cannot be called on `Pair<NoDisplay>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`NoDisplay: PartialOrd`
`NoDisplay: std::fmt::Display`
--> <实验目录>/src/u37e.rs:4:9
|
4 | impl<T: Display + PartialOrd> Pair<T> { // 只有 T 满足约束才有
| ^^^^^^^ ^^^^^^^^^^ -------
| | |
| | unsatisfied trait bound introduced here
| unsatisfied trait bound introduced here
note: the trait `std::fmt::Display` must be implemented
--> <rust 标准库源码>/library/core/src/fmt/mod.rs:1187:1
|
1187 | pub trait Display: PointeeSized {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider annotating `NoDisplay` with `#[derive(PartialEq, PartialOrd)]`
|
7 + #[derive(PartialEq, PartialOrd)]
…(共 36 行)写法 impl Trait 参数与约束是等价的,见impl Trait 参数与返回值。
生成的 add 函数符号(每个具体类型一份): 2 个 add::<f64>: fadd d0, d0, d1 ; ret add::<i32>: add w0, w1, w0 ; ret
单态化的详细代价见泛型单态化与静态分发与动态分发性能对比。