Implement Add on class which is not copy-able (self vs &self)

For demonstration purposes, say we have this code:

use std::ops;

struct BigClass {
    pub data: Vec<i32>,
}

impl ops::Add<i32> for BigClass {
    type Output = BigClass;
    fn add(self, rhs: i32) -> BigClass {
        BigClass { data: self.data.iter().map(|x| x + rhs).collect() }
    }
}

fn main() {
    let obj = BigClass { data: vec![1, 2, 3, 4, 5] };

    let obj_plus_2 = obj + 2;
    let obj_plus_5 = obj + 5;

    println!("{}", obj.data.iter().sum::<i32>());
    println!("{}", obj_plus_2.data.iter().sum::<i32>());
    println!("{}", obj_plus_5.data.iter().sum::<i32>());
}

I am trying to implement operator+ for BigClass. It seems that because add uses self and not &self my object gets moved, and hence we get an error:

  --> src\main.rs:67:22
   |
64 |     let obj = BigClass { data: vec![1, 2, 3, 4, 5] };
   |         --- move occurs because `obj` has type `BigClass`,
   |                  which does not implement the `Copy` trait
65 | 
66 |     let obj_plus_2 = obj + 2;
   |                      ------- `obj` moved due to usage in operator
67 |     let obj_plus_5 = obj + 5;
   |                      ^^^ value used here after move

Unfortunately, we cannot implement Copy for BigClass becasue Vec cannot be copied. Even if we could, I probably wouldn't want to, in case the internal vector is very big. Therefore, wouldn't it be much better to have operator+ use &self? Why can we not do this?

I understand that for small classes, Copy makes sense, but not for big classes. So how do I implement fn add(&self, rhs: i32) with &self? Or is there a reason one should not do this?

You can implement Add for &BigClass:

impl ops::Add<i32> for &BigClass {
    type Output = BigClass;
    fn add(self, rhs: i32) -> BigClass {
        BigClass { data: self.data.iter().map(|x| x + rhs).collect() }
    }
}
1 Like

Ah, perfect. Thank you!

I would keep the by value impl as well, and try to reuse the resources/allocations in that one if possible. That's usually helpful for efficiency, and the by ref impl may just end up being cloning and calling the by value impl, unless it can be done more efficiently some other way