Search code examples
ruststructoperation

Use Add in AddAssign


I have two structs say struct A and struct B. I have the Add implemented for A and B.

impl Add<&B> for A{
    type Output = A;
    fn add(self, rhs: &B) -> A{
    --snip--
}

Now, I want to implement the AddAssign, but I think there should be an idiomatic way to use Add. Something like:

impl AddAssign<&B> for A {
    fn add_assign(&mut self, rhs: &B) {
        *self = *self + rhs;
    }
}

Is there a way to do it?


Solution

  • It's a good idea to chain them together, but you're running to the issue of a dereference causing a move out of a borrowed value. It's typically easier to go the other way around, and implement AddAssign, then use that in Add. You can change the self to be mut self, which takes ownership as usual, but just allows it to be modified in place, then immediately returned:

    struct A;
    struct B;
    
    impl Add<&B> for A {
        type Output = A;
    
        fn add(mut self, rhs: &B) -> A {
            self += rhs;
            self
        }
    }
    
    impl AddAssign<&B> for A {
        fn add_assign(&mut self, rhs: &B) {
            todo!()
        }
    }
    

    If you really need them to be in that order, A has to be Copy and/or Clone. That could look like:

    #[derive(Clone, Copy)]
    struct A;
    struct B;
    
    impl Add<&B> for A {
        type Output = A;
    
        fn add(mut self, rhs: &B) -> A {
            todo!()
        }
    }
    
    impl AddAssign<&B> for A {
        fn add_assign(&mut self, rhs: &B) {
            *self = *self + rhs
        }
    }
    

    or

    #[derive(Clone)]
    struct A;
    struct B;
    
    impl Add<&B> for A {
        type Output = A;
    
        fn add(mut self, rhs: &B) -> A {
            todo!()
        }
    }
    
    impl AddAssign<&B> for A {
        fn add_assign(&mut self, rhs: &B) {
            *self = self.clone() + rhs
        }
    }