bigywater.tech
Rust · 36

Trait 定义与实现

trait 是 Rust 抽象的核心。这篇不讲概念,把 trait 的日常规则逐条跑出来:怎么定义与实现、默认方法、为什么要 use、关联常量与静态方法、同名冲突怎么办。每一条都有编译器的原话。

E0046
没有实现 trait 的必需方法
E0599
trait 没有在作用域内时方法找不到(并建议 use)
E0034
两个 trait 有同名方法时的歧义

定义与实现

实测 · 本机执行输出
  源码:
      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`.

trait 要在作用域内

实测 · 本机执行输出
  源码:
      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 的限制见孤儿规则。

分步演示

trait 的定义与实现
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。错误信息为原样的 rustc 1.98.1 输出
    • 没有验证:trait 的泛型参数与关联类型的差别(见后续文章)、泛型 trait 的多次实现、trait 对象(见 Trait Object 一篇)、async fn in trait
    京ICP备2026067502号-1京公网安备11010502063487号