Operators

RecipeCrates
std

Overload Operators like +, -, []

std

Operator overloading allows you to define how operators like +, -, *, and / behave for your custom types. This is done by implementing the corresponding traits from the std::ops module.

Common overloaded operators include Add⮳, Mul⮳ and Index⮳.

For example, to overload the + operator for a custom type, you would implement the Add trait:

use std::ops::Add;

// The struct we want to overload the '+' operator for.
// We derive the `Debug` trait to allow for easy printing with `{:?}`.
#[derive(Debug, Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

// Implementation of the `Add` trait for our `Point` struct.
impl Add for Point {
    // `type Output` specifies what type the `+` operator will return.
    type Output = Self;

    // This is the method that the `+` operator will call.
    // `self` is the left-hand side (e.g., `p1` in `p1 + p2`).
    // `rhs` (right-hand side) is the other operand (e.g., `p2`).
    fn add(self, rhs: Self) -> Self::Output {
        Point {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

fn main() {
    let p1 = Point { x: 1, y: 5 };
    let p2 = Point { x: 2, y: 3 };

    // Here we use the overloaded '+' operator:
    let p3 = p1 + p2;

    println!("{p1:?} + {p2:?} = {p3:?}");
    // Expected output:
    // Point { x: 1, y: 5 } + Point { x: 2, y: 3 } = Point { x: 3, y: 8 }
}

Add Function-like Behavior to a Custom Type

The std::ops module also provides traits for function-like / closure-like behavior: Fn, FnMut, and FnOnce. You can make your own types callable like functions by implementing these traits. This is unstable and requires nightly Rust:

#![feature(unboxed_closures, fn_traits)]

struct Adder {
    offset: i32,
}

use std::ops::FnOnce;

impl FnOnce<(i32,)> for Adder {
    type Output = i32;

    extern "rust-call" fn call_once(self, args: (i32,)) -> i32 {
        // args is a 1-tuple: `(i32,)`.
        self.offset + args.0
    }
}
use std::ops::FnMut;

impl FnMut<(i32,)> for Adder {
    extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 {
        self.offset + args.0
    }
}
use std::ops::Fn;

impl Fn<(i32,)> for Adder {
    extern "rust-call" fn call(&self, args: (i32,)) -> i32 {
        self.offset + args.0
    }
}

fn main() {
    let add_five = Adder { offset: 5 };

    // Call the type like a function:
    assert_eq!(add_five(3), 8);
    println!("5 + 3 = {}", add_five(3)); // prints "5 + 3 = 8".
}
  • Data Structures.
  • Drop.
  • Traits.