Operators
Overload Operators like +
, -
, []
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". }
Related Topics
- Data Structures.
- Drop.
- Traits.