1. 运算符重载
在上一篇文章《rust泛型编程范式》中我们讲了关联类型,例子如下
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
对于运算符重载,有些运算符trait定义了关联类型,有些没有定义了,什么时候用关联类型什么时候不用关联类型,我们分别看看,最后得出结论。
2. 带有关联类型的重载
2.1 一元运算符
- std::ops::Neg
- std::ops::Not
其定义如下:
trait Neg {
type Output;
fn neg(self) -> Self::Output;
}
trait Not {
type Output;
fn not(self) -> Self::Output;
}
一个例子如下:
#[derive(Clone, Copy, Debug)]
struct Complex<T> {
/// 复数的实部
re: T,
/// 复数的虚部
im: T,
}
use std::ops::Neg;
impl<T> Neg for Complex<T>
where
T: Neg<Output = T>,
{
type Output = Complex<T>;
fn neg(self) -> Complex<T> {
Complex {
re: -self.re,
im: -self.im,
}
}
}
2.1 二元运算符
- std::ops::Add
- std::ops::Sub
- std::ops::Mul
- std::ops::Div
- std::ops::Rem
- std::ops::BitAnd
- std::ops::BitOr
- std::ops::BitXor
- std::ops::Shl
- std::ops::Shr
其trait定义如下:
trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
trait BitXor<Rhs = Self> {
type Output;
fn bitxor(self, rhs: Rhs) -> Self::Output;
}
一个例子如下:
use std::ops::Add;
impl Add for Complex<i32> {
type Output = Complex<i32>;
fn add(self, rhs: Self) -> Self {
Complex {
re: self.re + rhs.re,
im: self.im + rhs.im,
}
}
}
2.3 索引(非mut)
- std::ops::Index
其trait定义如下
trait Index<Idx> {
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
3. 不带关联类型的重载
3.1 复合赋值运算符
- std::ops::AddAssign
- std::ops::SubAssign
- std::ops::MulAssign
- std::ops::DivAssign
- std::ops::RemAssign
- std::ops::BitAndAssign
- std::ops::BitOrAssign
- std::ops::BitXorAssign
- std::ops::ShlAssign
- std::ops::ShrAssign
其trait定义如下
trait AddAssign<Rhs = Self> {
fn add_assign(&mut self, rhs: Rhs);
}
一个例子如下:
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;
}
}
3.2 比较运算符
- std::cmp::PartialEq
- std::cmp::PartialOrd
其trait定义如下:
trait PartialEq<Rhs = Self>
where
Rhs: ?Sized,
{
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool {
!self.eq(other)
}
}
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 { ... }
}
一个例子如下:
impl<T: PartialEq> PartialEq for Complex<T> {
fn eq(&self, other: &Complex<T>) -> bool {
self.re == other.re && self.im == other.im
}
}
3.3 索引(mut)
- std::ops::IndexMut
其trait定义如下
trait IndexMut<Idx>: Index<Idx> {
fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
}
4 小结
什么时候用关联类型,观察上述trait定义,有两个重要发现:
- 当存在返回值且返回值为泛型定义是,定义了关联类型。
- 当不需要泛型返回值或者无返回值,就没有关联类型,无返回值一般是修改自身,因此参数是&mut self。
按照这两个发现,我们可以规范一下自己何时用trait的关联类型。