2

When implementing the Add trait (and a few others, like Mul, Sub, etc.) for a simple struct one has to fully consume the struct value, thus its later use is not possible.

At the same time, built in primitives (u8, usize, etc.) implement Add while allowing using it after add was called.

How can I implement Add for my structs to be able to use it after calling add?

use std::ops::Add;

struct I(usize);
impl Add for I {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        I(self.0 + rhs.0)
    }
}

fn main() {
    let a = 123;
    let b = a + a; // no error

    let a1 = I(123);
    let b1 = a1 + a1;

    println!("b={}", b);
}
error[E0382]: use of moved value: `a1`
  --> src/main.rs:16:19
   |
15 |     let a1 = I(123);
   |         -- move occurs because `a1` has type `I`, which does not implement the `Copy` trait
16 |     let b1 = a1 + a1;
   |              --   ^^ value used here after move
   |              |
   |              value moved here
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
dark_ruby
  • 7,646
  • 7
  • 32
  • 57

2 Answers2

3

You should be able to add #[derive(Copy, Clone)] to the struct, and then instead of consuming the value, it'll consume a copy.

Gray
  • 2,333
  • 1
  • 19
  • 24
1

You can impl Deref and dereference the value. This will work for types that are simple wrappers around an Add type.

use std::ops::{Add, Deref};

struct I(usize);
impl Add for I {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        I(self.0 + rhs.0)
    }
}

impl Deref for I {
    type Target = usize;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let a = 123;
    let b = a + a; // no error

    let a1 = I(123);

    // Note the dereferences.
    let b1 = *a1 + *a1;

    println!("b={}", b);
}

NB: Ryan's answer should suffice in this case, as usize is a clone type.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
jhpratt
  • 6,841
  • 16
  • 40
  • 50