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
3
  • You could impl Deref and use *a1, I imagine? Commented Jul 31, 2019 at 15:21
  • 1
    @jhpratt can you elaborate on your answer pls, and maybe provide an example implementation? Commented Jul 31, 2019 at 15:22
  • Ryan's answer should suffice, but I'll give you an example of what I mentioned as well. Commented Jul 31, 2019 at 15:25

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

3 Comments

I think it's quite odd to do that like that you just write a1.0 + a1.0 that doesn't really solve the problem if your type is not Copy
@Stargateur Things aren't always in the same module.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.