Skip to Content
Course content

38: Operator Overloading via Traits

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this happen to almost every developer moving from C++ or Python into Rust. You're building something—maybe a game engine or a physics simulation—and you create a simple struct to represent a coordinate. It feels natural to just add two coordinates together. Then, you hit this.

struct Vector2 {
    x: f64,
    y: f64,
}

fn main() {
    let v1 = Vector2 { x: 1.0, y: 2.0 };
    let v2 = Vector2 { x: 3.0, 4.0 };
    
    let result = v1 + v2; // ❌ Error here
    println!("Result: {}, {}", result.x, result.y);
}

The "cannot add" compiler wall

If you try to compile that, Rust will stop you dead. The error message is pretty blunt: cannot add `Vector2` to `Vector2`. It'll tell you that the trait std::ops::Add is not implemented for your type.

Coming from other languages, you might expect the compiler to just "figure it out" or allow you to define a method called add. But in Rust, the + symbol is actually syntactic sugar for a trait method. When you write a + b, Rust is effectively calling a.add(b). If the trait isn't implemented, the symbol simply doesn't exist for your type.

Teaching Rust how to add your structs

To fix this, we need to implement the Add trait from the std::ops module. The tricky part for beginners is the Output associated type. You have to explicitly tell Rust what the resulting type of the addition will be—even if it's just the same type you're adding.

use std::ops::Add;

#[derive(Debug, PartialEq)]
struct Vector2 {
    x: f64,
    y: f64,
}

impl Add for Vector2 {
    type Output = Vector2; // We tell Rust: "Adding two Vector2s results in a Vector2"

    fn add(self, other: Vector2) -> Vector2 {
        Vector2 {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

fn main() {
    let v1 = Vector2 { x: 1.0, y: 2.0 };
    let v2 = Vector2 { x: 3.0, y: 4.0 };
    
    let result = v1 + v2; // Now this works!
    println!("Result: {:?}", result);
}

I should mention something important here: notice that the add method takes self and other by value. This means v1 and v2 are consumed by the addition. If you try to use v1 again after the addition, you'll get a "use of moved value" error. This is where most people get frustrated with operator overloading in Rust.

Dealing with the ownership dance

In a real-world project, you rarely want to destroy your vectors just to add them. You probably want to add references to vectors. To do that, you have to implement the trait specifically for the reference types. It looks a bit repetitive, but it's the only way to keep your data alive.

Here is how I usually handle this when I want to avoid unnecessary allocations or moves:

impl Add for &Vector2 {
    type Output = Vector2;

    fn add(self, other: &Vector2) -> Vector2 {
        Vector2 {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

// Now you can do this:
let result = &v1 + &v2; 
// v1 and v2 are still available for use here!

I'll leave you with one tip: if you find yourself implementing Add, you almost certainly want to implement AddAssign (the += operator) as well. It's a separate trait, but it's usually more efficient because it modifies the existing struct in-place instead of creating a brand new one.




📋 Practical Task

Implementing a Complex Number Addition Engine

Create a struct named Complex that represents a complex number with two fields: re (real part) and im (imaginary part), both as f64.

Your task is to implement the following:

  • Implement std::ops::Add for Complex so that two complex numbers can be added using the + operator.
  • Implement std::ops::Sub for Complex so that they can be subtracted using the - operator.
  • Implement std::ops::AddAssign for Complex to support the += operator.

Verification: In your main function, create two Complex numbers, add them together, subtract one from the other, and use += to modify one of them. Print the results to the console to ensure the math is correct (e.g., (1.0 + 2.0i) + (3.0 + 4.0i) = 4.0 + 6.0i).

Rating
0 0

There are no comments for now.

to be the first to leave a comment.