3

I just started learning Rust, coming from a Java/JavaScript background, so bear with me because I am obviously missing something in my understanding of lifetimes.

fn main() {
    struct Appearance<'a> {
        identity:       &'a u64, 
        role:           &'a str
    };
    impl<'a> PartialEq for Appearance<'a> {
        fn eq(&self, other: &Appearance) -> bool {
            self.identity == other.identity && self.role == other.role
        }
    };
    let thing = 42u64;
    let hair_color = "hair color";
    let appearance = Appearance { 
        identity: &thing, 
        role: &hair_color 
    };
    let another_thing = 43u64;    
    let other_appearance = Appearance { 
        identity: &another_thing, 
        role: &hair_color 
    };
    println!("{}", appearance == other_appearance);
}

This is giving me a compilation error as the compiler reaches the other_appearance, telling me that another_thing does not live long enough. However, if I leave out the creation of other_appearance the program compiles and runs fine. Why am I getting this error?

nobody
  • 19,814
  • 17
  • 56
  • 77
Lars Rönnbäck
  • 788
  • 1
  • 5
  • 11

2 Answers2

6

The PartialEq trait has a type parameter that specifies the type of the right-hand side. Since you didn't specify it, it defaults to the same type as the left-hand side. This means that both sides are assumed to have the same lifetimes. This causes an error because another_thing is dropped before appearance, but other_appearance (which holds a reference to another_thing) is assumed to have the same lifetime as appearance.

You can fix this by using a different lifetime on the right-hand side:

impl<'a, 'b> PartialEq<Appearance<'b>> for Appearance<'a> {
    fn eq(&self, other: &Appearance<'b>) -> bool {
        self.identity == other.identity && self.role == other.role
    }
};
interjay
  • 107,303
  • 21
  • 270
  • 254
  • This is actually interesting because the instance created by `#[derive(PartialEq)]` has the same problem as OP's. – Peter Hall Jul 02 '17 at 17:05
  • As an aside, due to the fact that the values are dropped in the reverse order to them being declared, you can also fix this by swapping the order, i.e. use `other_appearance == appearance` instead of `appearance == other_appearance`. Yes, Rust has a few warts... – Peter Hall Jul 02 '17 at 17:06
  • Thank you! I need to dwell on the syntax, even if I understand conceptually what you said :) – Lars Rönnbäck Jul 02 '17 at 18:50
1

This seems to be a problem with lifetime inference/variance when combined with the == syntax sugar -- note that replacing the comparison with PartialEq::eq(&appearance, &other_appearance) works. I do not know whether this is a known bug.

Sebastian Ullrich
  • 1,170
  • 6
  • 10
  • Weird. This must be a bug. And it is particularly surprising because the behaviour is the same as OP's when you `#[derive(PartialEq)]` instead, which makes me wonder how it hasn't been found before. – Peter Hall Jul 02 '17 at 17:12
  • I stumbled across this question and was curious; the question's code compiles today with Rust 1.33.0. Some searching says it was fixed by this commit: https://github.com/rust-lang/rust/commit/1a7fb7dc78439a704f024609ce3dc0beb1386552 which was created to solve the problem described in this SO question: https://stackoverflow.com/questions/46857955/why-does-this-result-of-a-binary-operator-need-an-appropriate-lifetime – carols10cents Mar 18 '19 at 23:00