Associated Types and Advanced Traits
Operator Overloading
Operator overloading in Rust customizes the behavior of built-in operators (+, -, *, [], ==, <, !, etc.) for user-defined types by implementing the corresponding traits in std::ops and std::cmp.
Rules of Operator Overloading in Rust
- Trait-backed only: Every overloadable operator desugars to a method call on a trait in
std::opsorstd::cmp. - Fixed operator set: You cannot define brand-new operator symbols (such as
**or<=>). - Fixed precedence and associativity: Implementing
MulandAddalways obeys standard*before+precedence. - Excluded operators: Short-circuiting logical operators (
&&,||), assignment (=), range syntax (..,..=), and the error propagation operator (?, via unstableTry) cannot be overloaded in stable user code.
Overloadable Operators and Their Traits
| Category | Operators | Module & Trait Names |
|---|---|---|
| Binary arithmetic | +, -, *, /, % |
std::ops::{Add, Sub, Mul, Div, Rem} |
| Unary arithmetic / bitwise | -x, !x |
std::ops::{Neg, Not} |
| Bitwise & shift | &, |, ^, <<, >> |
std::ops::{BitAnd, BitOr, BitXor, Shl, Shr} |
| Compound assignment | +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= |
std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign} |
| Indexing & dereferencing | a[i], *x |
std::ops::{Index, IndexMut, Deref, DerefMut} |
| Equality & comparison | ==, !=, <, <=, >, >= |
std::cmp::{PartialEq, PartialOrd} |
Compiler Desugaring of Operators
When the compiler encounters an overloaded operator, it rewrites the expression into the underlying trait method call:
a + b ──> std::ops::Add::add(a, b)
a += b ──> std::ops::AddAssign::add_assign(&mut a, b)
-a ──> std::ops::Neg::neg(a)
a[i] ──> *std::ops::Index::index(&a, i)
a[i] = v ──> *std::ops::IndexMut::index_mut(&mut a, i) = v
a == b ──> std::cmp::PartialEq::eq(&a, &b)
use std::ops::{Add, Neg};
#[derive(Debug, Clone, Copy, PartialEq)]
struct Complex {
re: f64,
im: f64,
}
impl Add for Complex {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self {
re: self.re + rhs.re,
im: self.im + rhs.im,
}
}
}
impl Neg for Complex {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
re: -self.re,
im: -self.im,
}
}
}
fn main() {
let z1 = Complex { re: 1.5, im: -2.0 };
let z2 = Complex { re: 0.5, im: 4.0 };
let sum = z1 + z2;
let inverted = -sum;
println!("sum: {sum:?}");
println!("inverted: {inverted:?}");
}
sum: Complex { re: 2.0, im: 2.0 }
inverted: Complex { re: -2.0, im: -2.0 }