【Rust】 5. Trait 与运算符重载
一、Trait 基础概念
Trait 是 Rust 中定义共享行为的机制,类似于其他语言的接口,但有重要区别。
- 基本定义
trait Shape {fn area(&self) -> f64;
}
- 方法参数说明
-
&self 等价于 self: &Self
-
&mut self 等价于 self: &mut Self
-
self 等价于 self: Self
- 实现示例
struct Circle {radius: f64,
}impl Shape for Circle {fn area(&self) -> f64 {std::f64::consts::PI * self.radius * self.radius}
}
二、方法类型
- 实例方法
impl Circle {fn get_radius(&self) -> f64 {self.radius}
}
2.2 静态方法
impl Circle {fn get_area(this: &Self) -> f64 {std::f64::consts::PI * this.radius * this.radius}
}
三、扩展方法
可以为现有类型(包括内置类型)添加方法:
trait Double {fn double(&self) -> Self;
}impl Double for i32 {fn double(&self) -> i32 {self * 2}
}
四、泛型约束与分发机制
- 静态分发(编译时)
fn my_print<T: ToString>(v: T) {v.to_string();
}
4.2 动态分发(运行时)
fn dynamic_dispatch(animal: &dyn Animal) {animal.make_sound();
}
五、一致性原则(孤儿规则)
-
Impl 块必须与 trait 或类型在同一个 crate 中
-
防止外部 crate 为外部类型实现外部 trait
六、Trait 与接口的区别
Trait 不是具体类型,不能直接用作:
-
参数类型
-
返回值类型
-
变量类型
七、Derive 派生宏
自动实现常见 trait:
#[derive(Debug, Clone, PartialEq)]
struct Foo {data: i32,
}
支持的 trait:Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord 等
八、标记特质(Marker Traits)
标记特质是不含任何方法的特殊 trait,用于在类型系统中标记类型属性:
- 常见标记特质
-
Copy: 标记类型可以按位复制
-
Send: 标记类型可以安全地在线程间传递所有权
-
Sync: 标记类型可以安全地在线程间共享引用
-
Sized: 标记类型在编译时大小已知(几乎所有类型都自动实现)
// 手动实现标记特质
unsafe impl Send for MyType {}
unsafe impl Sync for MyType {}
- 自动 trait
Send 和 Sync 是自动 trait,满足条件时会自动实现:
// 这个结构体会自动实现 Send 和 Sync
#[derive(Debug)]
struct SafeData {value: i32,
}// 包含裸指针的结构体需要手动实现
struct UnsafeData {ptr: *mut i32,
}// 需要 unsafe 因为我们要保证线程安全
unsafe impl Send for UnsafeData {}
unsafe impl Sync for UnsafeData {}
九、类型计算与关联类型
- 关联类型(Associated Types)
在 trait 中定义类型占位符:
trait Graph {type Node; // 关联类型type Edge;fn nodes(&self) -> Vec<Self::Node>;fn edges(&self, node: &Self::Node) -> Vec<Self::Edge>;
}struct MyGraph;impl Graph for MyGraph {type Node = u32;type Edge = (u32, u32);fn nodes(&self) -> Vec<Self::Node> {vec![1, 2, 3]}fn edges(&self, node: &Self::Node) -> Vec<Self::Edge> {match node {1 => vec![(1, 2), (1, 3)],2 => vec![(2, 3)],_ => vec![],}}
}
- 泛型关联类型(GATs)
Rust 1.65+ 支持泛型关联类型:
trait Factory {type Product<T>;fn create<T>(&self, value: T) -> Self::Product<T>;
}struct MyFactory;impl Factory for MyFactory {type Product<T> = Option<T>;fn create<T>(&self, value: T) -> Self::Product<T> {Some(value)}
}
十、标准库重要 Trait
- Display vs Debug
-
Display: 用户友好输出,需手动实现
-
Debug: 调试输出,可自动派生
- ToString
自动为实现了 Display 的类型提供 to_string() 方法
3. 相等性比较
-
PartialEq: 部分相等比较
-
Eq: 完全相等比较(继承自 PartialEq)
- 排序比较
-
PartialOrd: 部分排序比较
-
Ord: 完全排序比较
- Clone 与 Copy
-
Clone: 显式深度拷贝
-
Copy: 标记 trait,表示按位拷贝
- Drop
资源清理 trait:
impl Drop for Point {fn drop(&mut self) {println!("Dropping point");}
}
- 类型转换 Trait
- From/Into
impl From<i32> for Point {fn from(x: i32) -> Self {Point { x, y: 0 }}
}
- TryFrom/TryInto
可失败的类型转换:
impl TryFrom<String> for Point {type Error = ParseError;fn try_from(s: String) -> Result<Self, Self::Error> {// 解析逻辑}
}
- FromStr
字符串解析:
impl FromStr for Point {type Err = ParseError;fn from_str(s: &str) -> Result<Self, Self::Err> {// 解析逻辑}
}
- AsRef
引用转换 trait:
fn takes_asref_str<S: AsRef<str>>(s: S) {let s: &str = s.as_ref();
}
十一、运算符重载
通过实现特定 trait 实现运算符重载:
- 算术运算符
-
Add: +
-
Sub: -
-
Mul: *
-
Div: /
use std::ops::Add;impl Add for Point {type Output = Self;fn add(self, other: Self) -> Self {Point {x: self.x + other.x,y: self.y + other.y,}}
}
- 比较运算符
通过实现 PartialEq, PartialOrd 等 trait 实现 ==, !=, <, > 等运算符
3. 索引运算符
通过实现 Index 和 IndexMut trait 实现 [] 运算符
十二、高级 Trait 特性
- Supertraits(父 trait)
一个 trait 可以要求实现者同时实现其他 trait:
trait Circle: Shape + Display {fn radius(&self) -> f64;
}
- Trait 对象与对象安全
只有对象安全的 trait 才能用作 trait 对象 (dyn Trait):
-
方法不能返回 Self
-
方法不能有泛型参数
// 对象安全的 trait
trait Draw {fn draw(&self);
}// 非对象安全的 trait(因为有泛型方法)
trait Processor {fn process<T>(&self, value: T);
}
十三、类型计算示例
- 使用泛型进行类型计算
trait Length {type Output;fn length(self) -> Self::Output;
}impl Length for &str {type Output = usize;fn length(self) -> Self::Output {self.len()}
}impl<T> Length for Vec<T> {type Output = usize;fn length(self) -> Self::Output {self.len()}
}
- 条件 trait 实现
use std::fmt::Display;struct Wrapper<T>(T);// 只为实现了 Display 的类型实现 Debug
impl<T: Display> std::fmt::Debug for Wrapper<T> {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {write!(f, "Wrapper({})", self.0)}
}
十四、总结
-
Trait 是 Rust 多态性的核心机制
-
标记特质用于在类型系统中标记类型属性
-
关联类型和 GATs 支持高级类型计算
-
区分静态分发与动态分发的适用场景
-
遵循一致性原则(孤儿规则)
-
合理使用 derive 派生宏减少样板代码
-
标准库 trait 为运算符重载和类型转换提供基础
-
Trait 对象 (dyn Trait) 提供运行时多态性
-
Supertraits 支持 trait 组合和继承
通过熟练掌握 trait 系统,可以编写出灵活、高效且类型安全的 Rust 代码。