Implementing Add
The std::ops::Add trait overloads the binary addition operator (+), allowing custom types to support homogeneous addition (T + T), heterogeneous addition (T + U), and reference-based addition (&T + &T).
Trait Definition
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
Rhs = Selfis a default generic type parameter specifying the right-hand operand's type.type Outputis an associated type specifying the result type ofself + rhs.add(self, rhs: Rhs)takes bothselfandrhsby value.
Homogeneous Addition (Rhs = Self)
When adding two values of the same type, omit the <Rhs> argument on Add:
use std::ops::Add;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Bytes(u64);
impl Add for Bytes {
type Output = Bytes;
fn add(self, rhs: Bytes) -> Self::Output {
Bytes(self.0 + rhs.0)
}
}
fn main() {
let a = Bytes(1024);
let b = Bytes(2048);
println!("Total: {:?}", a + b);
}
Total: Bytes(3072)
Heterogeneous Addition (Rhs != Self)
Specify a concrete Rhs type on Add<Rhs> to support adding two distinct types (such as adding a Duration offset to a Timestamp):
use std::ops::Add;
#[derive(Debug, Clone, Copy)]
struct Meters(f64);
#[derive(Debug, Clone, Copy)]
struct Centimeters(f64);
impl Add<Centimeters> for Meters {
type Output = Meters;
fn add(self, rhs: Centimeters) -> Meters {
Meters(self.0 + rhs.0 / 100.0)
}
}
fn main() {
let base = Meters(2.5);
let delta = Centimeters(75.0);
let total: Meters = base + delta;
println!("Total distance: {total:?}");
}
Total distance: Meters(3.25)
Note that impl Add<Centimeters> for Meters enables Meters + Centimeters, not Centimeters + Meters. If addition should be commutative, also implement Add<Meters> for Centimeters.
Implementing Add for References (&T + &T)
For non-Copy types that own heap data (such as big integers, matrices, or polynomials), implementing Add on &T allows callers to write &a + &b without moving and consuming a and b:
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Polynomial {
coeffs: Vec<i64>,
}
impl Add for &Polynomial {
type Output = Polynomial;
fn add(self, rhs: &Polynomial) -> Polynomial {
let len = self.coeffs.len().max(rhs.coeffs.len());
let mut coeffs = Vec::with_capacity(len);
for i in 0..len {
let a = self.coeffs.get(i).copied().unwrap_or(0);
let b = rhs.coeffs.get(i).copied().unwrap_or(0);
coeffs.push(a + b);
}
Polynomial { coeffs }
}
}
fn main() {
let p1 = Polynomial { coeffs: vec![1, 2, 3] };
let p2 = Polynomial { coeffs: vec![4, 5] };
// Borrowed addition preserves p1 and p2:
let sum = &p1 + &p2;
println!("p1: {:?}", p1.coeffs);
println!("p2: {:?}", p2.coeffs);
println!("sum: {:?}", sum.coeffs);
}
p1: [1, 2, 3]
p2: [4, 5]
sum: [5, 7, 3]