21、Operator overloading(运算符重载)

运算符重载

现在我们对于traits有了基本的了解,回到运算符重载上来。运算符重载就是对一些运算符(比如+,-,*,/,==,!=等)的行为进行自定义。

运算符是traits

在Rust里,运算符就是traits。

对于每一个运算符,都有相应的trait来定义这个运算符的行为。通过对我们自己的类型实施这个trait,我们就可以解锁响应运算符的用法。

 

例如,PartialEqtrait定义了==!=的行为:

// The `PartialEq` trait definition, from Rust's standard library
// (It is *slightly* simplified, for now)
pub trait PartialEq {
    // Required method
    //
    // `Self` is a Rust keyword that stands for 
    // "the type that is implementing the trait"
    fn eq(&self, other: &Self) -> bool;

    // Provided method
    fn ne(&self, other: &Self) -> bool { ... }
}

 

当我们编写x==y的时候,编译器会为x和y的类型寻找PartialEqtrait的实现,并将x==y替换为x.eq(y)。这就是语法糖!

 

这是基本操作符与trait的对应关系

Operator Trait
+ Add
- Sub
* Mul
/ Div
% Rem
== and != PartialEq
<, >, <=, and >= PartialOrd

算术运算符位于std::ops模块当中,而比较运算符位于std::cmp模块当中。

默认实现

image-20250909113829704

PartialEq的注释指出“ne是一个提供的方法(ne is a provided method)”

这句话的意思就是PartialEq在trait定义中,为ne提供了一个默认实现,就是定义片段中{…}这个省略块

 

可以看到就是上面的源代码:

pub trait PartialEq {
    fn eq(&self, other: &Self) -> bool;

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

这正是我们预料到的,ne就是eq的否定。

因为eq提供了默认实现,所以在为我们的自定义类型实现PartialEq的时候可以跳过ne,只实现eq即可。

 

比如下面这个例子:

struct WrappingU8 {
    inner: u8,
}

impl PartialEq for WrappingU8 {
    fn eq(&self, other: &WrappingU8) -> bool {
        self.inner == other.inner
    }
    
    // No `ne` implementation here
    // 这里没有`ne`的代码实现
}

 

不过要注意,默认实现其实也是可以自定义逻辑的,只需要我们手动实现ne方法即可:

struct MyType;

impl PartialEq for MyType {
    fn eq(&self, other: &MyType) -> bool {
        // Custom implementation
    }

    fn ne(&self, other: &MyType) -> bool {
        // Custom implementation
    }
}

练习

这次的练习,是让我们为Ticket实现eq方法,以实现Ticket的==!=操作,结合刚才所学到的内容

image-20250909114706198

我们可以很轻松的编码:

impl PartialEq for Ticket {
    fn eq(&self, other: &Ticket) -> bool {
        self.title == other.title&& self.description == other.description&& self.status == other.status
    }
}

让三个String字段都相等,即相等就好了。不得不说,Rust确实非常巧妙,尽管其他各种语言C/C++等,也都实现了运算符重载,但是我觉得Rust是做的最优雅的!

 

这一节的学习就到这里了

 

阅读剩余
THE END