淡若轻风

博客园 首页 新随笔 联系 订阅 管理
Trait 是 Rust 最核心、最独特、最强大的特性之一,你可以把它理解为:
定义行为的接口 / 契约 —— 告诉编译器「某种类型能做什么」,但不关心它具体是什么。
 
它类似其他语言的:
  • Java / C# 的 Interface(接口)
  • C++ 的 抽象类
  • Go 的 Interface
但 Rust 的 Trait 更强大,支持默认实现、静态分发、动态分发、关联类型、泛型约束等。

一、最简单的定义:Trait 是什么?

一句话:
Trait = 方法签名的集合 + 可选的默认实现
用来描述一组通用能力,任何类型只要实现这个 Trait,就拥有这个能力。
trait Speak {
    // 方法签名(没有实现)
    fn speak(&self);
}

// 给人类实现这个 Trait
struct Person;
impl Speak for Person {
    fn speak(&self) {
        println!("我是人!");
    }
}

// 给狗狗实现这个 Trait
struct Dog;
impl Speak for Dog {
    fn speak(&self) {
        println!("汪汪!");
    }
}

作用:

不管是 Person 还是 Dog,只要实现了 Speak,就能调用 .speak()。

二、Trait 的 3 种核心用法

1. 定义方法 + 强制实现(抽象方法)

只写方法签名,不写实现,必须由类型自己实现。
trait Calculate {
    fn area(&self) -> f64;
}

2. 定义方法 + 默认实现(自带功能)

Trait 可以直接提供方法实现,类型可以选择用默认 or 重写。
trait Greet {
    // 默认实现
    fn greet(&self) {
        println!("你好!");
    }
}

struct Student;
// 直接使用默认实现,不用写任何代码
impl Greet for Student {}

3. 关联函数(不带 &self)

类似静态方法:
trait Creator {
    fn new() -> Self;  // 关联函数
}

三、Trait 最常用场景(必掌握)

1. 代码复用:不同类型共享同一套行为

比如:打印、序列化、比较、克隆、调试……
 
Rust 标准库大量使用:
  • Debug:打印调试 {:?}
  • Clone:克隆对象
  • Copy:拷贝值
  • Eq / PartialEq:相等比较
  • Ord:排序
// 自动派生标准 Trait
#[derive(Debug, Clone, PartialEq)]
struct User {
    name: String,
}

2. 泛型约束:限制类型必须具备某种能力

这是 Rust 强类型安全的关键!
// 只有实现了 Speak 的类型,才能调用这个函数
fn make_speak<T: Speak>(thing: T) {
    thing.speak();
}

make_speak(Person);  // ✅ 可以
make_speak(Dog);     // ✅ 可以

更优雅的写法:

fn make_speak(thing: impl Speak) {
    thing.speak();
}

3. 动态分发:统一处理不同类型(多态)

// 接收任意实现了 Speak 的类型
fn say_hello(thing: &dyn Speak) {
    thing.speak();
}

let p = Person;
let d = Dog;
say_hello(&p);
say_hello(&d);

dyn Trait = 动态分发,运行时决定调用哪个实现。

四、Trait 的高级能力(Rust 独有)

1. 关联类型(Associated Types)

在 Trait 里定义占位类型,实现时再指定具体类型。
trait Iterator {
    type Item;   // 关联类型
    fn next(&mut self) -> Option<Self::Item>;
}

2. 方法重载(同名方法不同实现)

trait A { fn do_something(&self); }
trait B { fn do_something(&self); }

struct MyType;
impl A for MyType { ... }
impl B for MyType { ... }

调用时用完全限定语法:

MyType::do_something(&obj);  // 自动选
A::do_something(&obj);       // 明确调用 A

3. Trait 继承(Supertraits)

一个 Trait 可以继承另一个 Trait:
trait Animal: Speak {
    // 实现 Animal 必须先实现 Speak
}

4. 空白实现(Marker Traits)

没有任何方法,仅做标记:
unsafe trait Send {}  // 表示可以跨线程安全传递

五、Trait 两种分发方式(面试常考)

1. 静态分发(impl Trait / 泛型)

  • 编译期生成对应代码
  • 速度极快(零开销)
  • 代码体积稍大

2. 动态分发(dyn Trait)

  • 运行时查找方法
  • 有微小性能开销
  • 代码体积小
  • 适合存放不同类型到同一个集合:
let list: Vec<Box<dyn Speak>> = vec![Box::new(Person), Box::new(Dog)];

六、完整示例:从定义到使用

// 1. 定义 Trait
trait Shape {
    fn area(&self) -> f64;
    
    // 默认实现
    fn print_info(&self) {
        println!("面积是:{}", self.area());
    }
}

// 2. 给圆形实现
struct Circle(f64);
impl Shape for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.0 * self.0
    }
}

// 3. 给正方形实现
struct Square(f64);
impl Shape for Square {
    fn area(&self) -> f64 {
        self.0 * self.0
    }
}

// 4. 统一使用
fn print_area(s: impl Shape) {
    s.print_info();
}

fn main() {
    let c = Circle(2.0);
    let s = Square(3.0);
    
    print_area(c);
    print_area(s);
}

七、一句话总结 Trait 作用

  1. 定义能力:类型能做什么
  2. 代码复用:不同类型共享行为
  3. 泛型约束:保证类型安全
  4. 多态:统一处理不同类型
  5. Rust 接口的唯一形式

总结

  • Trait = 接口 = 行为契约
  • 可以有方法签名 + 默认实现
  • 支持静态 / 动态分发
  • 是 Rust 泛型、安全、复用的基石
  • 标准库大量使用:Debug、Clone、Iterator 等

 

posted on 2026-05-30 17:52  淡若轻风  阅读(50)  评论(0)    收藏  举报