trait 是 Rust 抽象的核心。这篇不讲概念,把 trait 的日常规则逐条跑出来:怎么定义与实现、默认方法、为什么要 use、关联常量与静态方法、同名冲突怎么办。每一条都有编译器的原话。
源码:
1 | trait Shape {
2 | fn area(&self) -> f64;
3 | fn name(&self) -> String;
4 | fn describe(&self) -> String { format!("{} 面积 {:.2}", self.name(), self.area()) } // 默认实现
5 | }
6 | struct Circle(f64);
7 | struct Rect { w: f64, h: f64 }
8 | impl Shape for Circle { fn area(&self) -> f64 { 3.14159 * self.0 * self.0 } fn name(&self) -> String { "圆".into() } }
9 | impl Shape for Rect {
10 | fn area(&self) -> f64 { self.w * self.h }
11 | fn name(&self) -> String { "矩形".into() }
12 | fn describe(&self) -> String { format!("{}(覆盖了默认实现)", self.name()) }
13 | }
14 | fn main() {
15 | println!("{}", Circle(1.0).describe());
16 | println!("{}", Rect { w: 2.0, h: 3.0 }.describe());
17 | }
编译:成功
运行(退出码 0):
圆 面积 3.14
矩形(覆盖了默认实现)
源码:
1 | trait Shape { fn area(&self) -> f64; fn name(&self) -> String; }
2 | struct Circle(f64);
3 | impl Shape for Circle { fn area(&self) -> f64 { self.0 } }
4 | fn main() {}
编译:失败
error[E0046]: not all trait items implemented, missing: `name`
--> <实验目录>/src/u36b.rs:3:1
|
1 | trait Shape { fn area(&self) -> f64; fn name(&self) -> String; }
| ------------------------- `name` from trait
2 | struct Circle(f64);
3 | impl Shape for Circle { fn area(&self) -> f64 { self.0 } }
| ^^^^^^^^^^^^^^^^^^^^^ missing `name` in implementation
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0046`. 源码:
1 | mod geometry {
2 | pub trait Area { fn area(&self) -> f64; }
3 | pub struct Sq(pub f64);
4 | impl Area for Sq { fn area(&self) -> f64 { self.0 * self.0 } }
5 | }
6 | fn main() {
7 | let s = geometry::Sq(3.0);
8 | println!("{}", s.area());
9 | }
编译:失败
error[E0599]: no method named `area` found for struct `Sq` in the current scope
--> <实验目录>/src/u36c.rs:8:22
|
2 | pub trait Area { fn area(&self) -> f64; }
| ---- the method is available for `Sq` here
3 | pub struct Sq(pub f64);
| ------------- method `area` not found for this struct
...
8 | println!("{}", s.area());
| ^^^^ method not found in `Sq`
|
= help: items from traits can only be used if the trait is in scope
help: trait `Area` which provides `area` is implemented but not in scope; perhaps you want to import it
|
1 + use crate::geometry::Area;
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.
编译:成功
运行(退出码 0):
9 源码:
1 | trait Animal {
2 | const LEGS: u32;
3 | fn new(name: &str) -> Self;
4 | fn name(&self) -> String;
5 | fn legs(&self) -> u32 { Self::LEGS }
6 | }
7 | struct Dog(String); struct Bird(String);
8 | impl Animal for Dog { const LEGS: u32 = 4; fn new(n: &str) -> Self { Dog(n.into()) } fn name(&self) -> String { self.0.clone() } }
9 | impl Animal for Bird { const LEGS: u32 = 2; fn new(n: &str) -> Self { Bird(n.into()) } fn name(&self) -> String { self.0.clone() } }
10 | fn make<T: Animal>(n: &str) -> T { T::new(n) }
11 | trait Double { fn double(&self) -> Self; }
12 | impl Double for i32 { fn double(&self) -> i32 { self * 2 } }
13 | fn main() {
14 | let d: Dog = make("旺财"); let b = make::<Bird>("小鸟");
15 | println!("{} 有 {} 条腿,{} 有 {} 条腿", d.name(), d.legs(), b.name(), b.legs());
16 | println!("为 i32 实现自己的 trait:21.double() = {}", 21.double());
17 | }
编译:成功
运行(退出码 0):
旺财 有 4 条腿,小鸟 有 2 条腿
为 i32 实现自己的 trait:21.double() = 42关联类型见Associated Type;trait 约束见Trait Bound。
源码:
1 | trait Pilot { fn fly(&self) -> &'static str; }
2 | trait Wizard { fn fly(&self) -> &'static str; }
3 | struct Human;
4 | impl Pilot for Human { fn fly(&self) -> &'static str { "机长广播" } }
5 | impl Wizard for Human { fn fly(&self) -> &'static str { "施法飞行" } }
6 | impl Human { fn fly(&self) -> &'static str { "挥手(Human 自己的方法)" } }
7 | fn main() {
8 | let h = Human;
9 | println!("{}", h.fly()); // 固有方法优先
10 | println!("{}", Pilot::fly(&h));
11 | println!("{}", <Human as Wizard>::fly(&h));
12 | }
编译:成功
运行(退出码 0):
挥手(Human 自己的方法)
机长广播
施法飞行
源码:
1 | trait Pilot { fn fly(&self) -> &'static str; }
2 | trait Wizard { fn fly(&self) -> &'static str; }
3 | struct Human;
4 | impl Pilot for Human { fn fly(&self) -> &'static str { "机长广播" } }
5 | impl Wizard for Human { fn fly(&self) -> &'static str { "施法飞行" } }
6 | fn main() { println!("{}", Human.fly()); }
编译:失败
error[E0034]: multiple applicable items in scope
--> <实验目录>/src/u36g.rs:6:34
|
6 | fn main() { println!("{}", Human.fly()); }
| ^^^ multiple `fly` found
|
note: candidate #1 is defined in an impl of the trait `Pilot` for the type `Human`
--> <实验目录>/src/u36g.rs:4:24
|
4 | impl Pilot for Human { fn fly(&self) -> &'static str { "机长广播" } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: candidate #2 is defined in an impl of the trait `Wizard` for the type `Human`
--> <实验目录>/src/u36g.rs:5:25
|
5 | impl Wizard for Human { fn fly(&self) -> &'static str { "施法飞行" } }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the method for candidate #1
|
6 - fn main() { println!("{}", Human.fly()); }
6 + fn main() { println!("{}", Pilot::fly(&Human)); }
|
help: disambiguate the method for candidate #2
|
6 - fn main() { println!("{}", Human.fly()); }
…(共 30 行)能为哪些类型实现哪些 trait 的限制见孤儿规则。