8.5 运算符重载与 Deref 强制转换
Rust 不支持传统意义上的运算符重载,但允许通过实现特定的标准库 trait来定制类型对运算符的行为。此外,通过 Deref 和 DerefMut trait,Rust 能自动将智能指针“解引用”为所指向的类型,并触发Deref 强制转换(Deref coercion),使自定义类型在使用上如同原生引用一样自然。
运算符重载
Rust 将运算符(如 +、-、*、== 等)映射到对应的 trait。例如:
a + b→ 调用Add::add(a, b)a == b→ 调用PartialEq::eq(&a, &b)-a→ 调用Neg::neg(a)
要让自定义类型支持某个运算符,只需实现对应的 trait。
例如,为二维点实现加法:
use std::ops::Add;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 3, y: 4 };
let p3 = p1 + p2; // 调用 Add::add
println!("{:?}", p3); // Point { x: 4, y: 6 }
也可以实现不同类型之间的运算,例如点加偏移量:
struct Offset(i32, i32);
impl Add<Offset> for Point {
type Output = Point;
fn add(self, offset: Offset) -> Point {
Point {
x: self.x + offset.0,
y: self.y + offset.1,
}
}
}
常见可重载的运算符 trait 包括:
- 算术:
Add,Sub,Mul,Div,Rem - 比较:
PartialEq,Eq,PartialOrd,Ord - 位运算:
BitAnd,BitOr,Shl,Shr - 索引:
Index,IndexMut - 解引用:
Deref,DerefMut
注意:Rust 不允许创建新运算符,只能重载已有运算符的语义。
Deref 强制转换
Deref trait 定义了如何将一个类型“解引用”为另一个类型。标准库中的 Box<T>、Rc<T>、String 和 Vec<T> 都实现了 Deref。
例如,String 实现了 Deref<Target = str>,因此可以将 &String 自动转换为 &str:
fn takes_str(s: &str) { /* ... */ }
let s = String::from("hello");
takes_str(&s); // ✅ 自动将 &String 转为 &str
这种自动转换称为 Deref 强制转换。当函数期望 &T,但传入的是 &U,且 U 实现了 Deref<Target = T> 时,Rust 会自动插入 * 解引用操作,直到类型匹配。
自定义 Deref
你可以为自己的智能指针类型实现 Deref:
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let x = 5;
let box_x = MyBox::new(x);
assert_eq!(5, *box_x); // *box_x 等价于 *(box_x.deref())
这里,*box_x 实际调用 box_x.deref(),返回 &i32,再解引用得到 i32。
DerefMut 与可变解引用
若需可变访问,还需实现 DerefMut:
use std::ops::{Deref, DerefMut};
impl<T> DerefMut for MyBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
这样就能在需要 &mut T 的地方传入 &mut MyBox<T>。
使用场景与注意事项
- 运算符重载应保持直观语义,避免违反用户预期(如用
+表示连接而非加法); - Deref 强制转换主要用于智能指针类型,不应滥用(例如,不要为普通结构体实现
Deref来“省略字段访问”); Deref应满足“继承”语义:MyBox<T>应表现得像T本身,而不是仅仅提供便捷访问。
小结
通过实现标准 trait,Rust 允许安全地定制运算符行为;而 Deref 机制则使智能指针能无缝融入现有 API。这两者共同提升了自定义类型的表达力和易用性,同时保持语言的一致性和零成本抽象原则。正确使用它们,可以让库的接口更加自然、符合直觉。