10 - 操作符重载
-
操作符重载:让自己定义的类型支持算术和其他操作。
-
支持操作符重载的特型:
类别 特型 操作符 一元操作符 std::ops::Neg
std::ops::Not
-x
!x
算术操作符 std::ops::Add
std::ops::Sub
std::ops::Mul
std::ops::Div
std::ops::Rem
x + y
x - y
x * y
x / y
x % y
位操作符 std::ops::BitAnd
std::ops::BitOr
std::ops::BitXor
std::ops::Shl
std::ops::Shr
x & y
x - y
x * y
x / y
x % y
复合赋值算术操作符 std::ops::AddAssign
std::ops::SubAssign
std::ops::MulAssign
std::ops::DivAssign
std::ops::RemAssign
x += y
x -= y
x *= y
x /= y
x %= y
复合赋值位操作符 std::ops::BitAndAssign
std::ops::BitOrAssign
std::ops::BitXorAssing
std::ops::ShlAssign
std::ops::ShrAssign
x &= y
`x比较 std::cmp::PartialEq
std::cmp::PartialOrd
x == y
、x != y
x < y
、x <= y
、x > y
、x >= y
索引 std::ops::Index
std::ops::IndexMut
x[y]
、&x[y]
x[y] = z
、&mut x[y]
10.1 - 算术与位操作符
10.1.1 - 一元操作符
-
*
引用操作符 -
std::ops::Neg
特型:实现一元取反操作符-
。trait Neg { type Output; fn neg(self) -> Self::Output; }
-
std::ops::Not
特型:实现一元非操作符!
。trait Not { type Output; fn not(self) -> Self::Output; }
-
对复数值取反的泛型实现:
use std::ops::Neg; impl<T, O> Neg for Complex<T> where T: Neg<Output=O> { type Output = Complex<O>; fn neg(self) -> Complex<O> { Complex { re: -self.re; im: -self.im } } }
10.1.2 - 二元操作符
-
Rust 的所有数值类型都实现了算术操作符;
-
Rust 的整数类型和
bool
实现了位操作符。 -
它们也实现了接受对这些类型的引用作为一个或两个操作数的逻辑。
-
算术操作符和位操作符的特型都有统一的形式:
// 针对^操作符的std::ops::BitXor的定义 trait BitXor<RHS=Self> { type Output; fn bitxor(self, rhs: RHS) -> Self::Output; }
-
使用
+
操作符可以将一个String
和一个&st
切片或另一个String
拼接起来。但是 Rust 不允许+
的左操作数是&str
,目的是阻止通过重复小的左操作数来构建长字符串。(会造成性能隐患:所需时间与最终字符串长度的平方成正相关) -
要一段一段的拼接字符串,最好使用
write!
。
10.1.3 - 复合赋值操作符
-
Rust 的所有数值类型都实现了算术复合赋值操作符;
-
Rust 的整数类型和
bool
还实现了位复合赋值操作符。 -
对
Complex
类型进行AddAssign
的泛型实现:use std::ops::AddAssign; impl<T> AddAssign for Complex<T> where T: AddAssign<T> { fn add_assign(&mut self, rhs: Complex<T>) { self.re += rhs.re; self.im += rhs.im; } }
-
复合操作符的内置特型与对应的二元操作符的内置特型相互独立。
-
实现
std::ops::Add
不会自动实现std::ops::AddAssign
。如果要让自定义类型作为+=
操作符的左操作数,那么必须实现AddAssign
。 -
与二元特型
Shl
和Shr
类似,ShlAssign
和ShrAssign
特型:没有将RHS
类型参数默认为Self
,所以实现时必须明确给出右操作数的类型。
10.2 - 相等测试
-
==
和!=
是对调用std::cmp::PartialEq
特型方法eq
和ne
的简写:assert_eq!(x == y, x.eq(&y)); assert_eq!(x != y, x.ne(&y));
-
std::cmp::PartialEq
的定义:trait PartialEq<Rhs: ?Sized = Self> { fn eq(&self, other: &Rhs) -> bool; fn ne(&self, other: &Rhs) -> bool { !self.eq(other) } }
-
Complex
的完整实现:impl<T: PartialEq> PartialEq for Complex<T> { fn eq(&self, other: &Complex<T>) -> bool { self.re == other.re && self.im == other.im } }
-
Rhs: ?Sized
放宽了 Rust 对类型参数必须有大小的限制,以支持PartialEq<str>
或PartialEq<T>
这样的特型。方法eq
和ne
接收&Rhs
类型的参数,可以比较&str
和&[T]
。 -
标准库将
Eq
定义为PartialEq
的扩展,且没有定义新方法:trait Eq: PartialEq<Self> { }
-
为
Complex
类型实现Eq
:impl<T: Eq> Eq for Complex<T> { }
-
在
Complex
类型定义的derive
属性中包含Eq
也可以实现:#[derive(Clone, Copy, Debug, Eq, PartialEq)] struct Complex<T> { ... }
-
10.3 - 顺序比较
Rust 通过特型 std::cmp::PartialOrd
规定了顺序比较操作符 <
、>
、<=
和 >=
的行为:
trait PartialOrd<Rhs = Self>: PartialEq<Rhs> where Rhs: ?Sized {
fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
fn lt(&self, other: &Rhs) -> bool { ... }
fn le(&self, other: &Rhs) -> bool { ... }
fn gt(&self, other: &Rhs) -> bool { ... }
fn ge(&self, other: &Rhs) -> bool { ... }
}
10.4-Index 与 IndexMut
-
通过实现
std::ops::Index
和std::ops::IndexMut
特型,可以对相应类型使用类似a[i]
这样的索引表达式。trait Index<Idx> { type Output: ?Sized; fn index(&self, index: Idx) -> &Self::Output; } trait IndexMut<Idx>: Index<Idx> { fn index_mut(&mut self, index: Idx) -> &mut Self::Output; }
-
a[i..j]
是下述表达式的简写:*a.index(std::ops::Range { start: i, end: j })
10.5 - 其他操作符
*val
解引用操作符和.
调用方法的点操作符,可以使用 Deref
和 DerefMut
特型来重载。
下述操作符都不支持重载:
- 错误检查操作符
?
只能用于Result
值; - 逻辑操作符
&&
和||
仅限于布尔值; ..
操作符只能用于创建Range
值;&
操作符只能借用引用;=
操作符只能转移或复制值。f(x)
函数调用操作符不支持重载,如果要一个可调用的值,通常写一个闭包就可以了。
详见《Rust 程序设计》(吉姆 - 布兰迪、贾森 - 奥伦多夫著,李松峰译)第十二章
原文地址