3

There are lots of similar questions, but I couldn't find the answer to my exact question.

In my Rust code, I have a generic type and want to implement a method that takes a reference to another instance of the that type, and then another method that consumes its argument but does exactly the same thing as the first one:

#[derive(Debug, PartialEq, Clone)]
pub struct Wrapper<T> {
    v: T,
}

impl<T> Wrapper<T> {
    pub fn f_ref(&self, _other: &Wrapper<T>) { /* ... */ }
    pub fn f_consume(&self, other: Wrapper<T>) {
        self.f_ref(&other)
    }
}

It compiles just fine.

Now I want to do basically the same, but while implementing a trait. First, the function that takes a reference:

use std::ops::AddAssign;

impl<'a, T> AddAssign<&'a Wrapper<T>> for Wrapper<T> where T: AddAssign<&'a T> {
    fn add_assign(&mut self, other: &'a Wrapper<T>) {
        self.v += &other.v;
    }
}

#[test]
fn test() {
    let mut a = Wrapper { v: 1_i32 };
    let b = Wrapper { v: 2 };
    a += &b;
    drop(b);
    assert_eq!(a, Wrapper { v: 3 });
}

It works, too.

Now I want to implement AddAssign for Wrapper<T> based on the implementation of AddAssign<&Wrapper<T>> that I already have. I understand that if T has references in it, it will cause trouble, so I make sure it has 'static lifetime. I'm OK with it: in my program, I expect T to be something like an owned matrix of numbers wrapped in some custom struct.

impl<'a, T> AddAssign for Wrapper<T> where T: 'static + AddAssign<&'a T>, Wrapper<T>: 'static {
    fn add_assign(&mut self, other: Wrapper<T>) {
        *self += &other;
    }
}

And it fails. The compiler says that other must stay valid after we used a reference to it to in a += expression. But when we used such a reference in the test() function above and dropped b there (which played the role of other here) and used the result later, the compiler agreed it's OK. Why?

I suspect that I need to specify some additional trait bounds for T or Wrapper<T> but don't understand what these bound should be.

Code in playground.

  • 3
    To apply the duplicate here: use either `where T: for<'a> AddAssign<&'a T>` or `where Wrapper: for<'a> AddAssign<&'a Wrapper>` (what I would write). [Example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e37a241f43aaa5b9f3b7c75f39015a34) – trent Jan 12 '19 at 14:50
  • [Borrowed value does not live long enough when iterating over a generic value with a lifetime on the function body](https://stackoverflow.com/q/53485574/3650362) has the same error for the same reason. [How does for<> syntax differ from a regular lifetime bound?](https://stackoverflow.com/q/35592750/3650362) is another related question. – trent Jan 12 '19 at 14:52
  • Oh my rusty god. Thanks! – colt_browning Jan 12 '19 at 14:53
  • 1
    You're welcome! You're not wrong that there are lots of similar questions, but HRTBs are a thing that don't make much sense until you find you need them, and hard to search for unless you already know what they are. Hopefully marking this question as a duplicate will help others find the same answers. – trent Jan 12 '19 at 15:00

0 Answers0