Compiler claims equality for references not implemented

Equality for references is implemented according to the docs, but in the following scenario (simplified from the original), the compiler seems to think it's not. Please help me understand why.

struct Node<T>(T);

pub struct Iter<'a, T: 'a> {
    front_link: Option<&'a Node<T>>,
    back_link: Option<&'a Node<T>>,
}

impl<'a, T> Iter<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        let done0 = self.front_link == self.back_link; // ERROR
        self.front_link.take().map(|node_ref| {
            let done1 = Some(node_ref) == self.back_link; // ERROR
            let done2 = match (self.back_link) {
                Some(nref) => {
                    //let i: u32 = node_ref; // Error shows that node_ref: &Node<T>
                    //let i: u32 = nref;     // Error shows that nref: &Node<T>
                    nref == node_ref // ERROR
                },
                None => false
            };
        });
        None
    }
}

fn main() { }

The errors I get are

error: binary operation `==` cannot be applied to type `core::option::Option<&'a Node<T>>` [E0369]
    let done0 = self.front_link == self.back_link;
                ^~~~~~~~~~~~~~~

error: binary operation `==` cannot be applied to type `core::option::Option<&Node<T>>` [E0369]
  let done1 = Some(node_ref) == self.back_link;
              ^~~~~~~~~~~~~~

error: binary operation `==` cannot be applied to type `&Node<T>` [E0369]
          nref == node_ref
          ^~~~

The line in question from the docs is:

impl<'a, A> Eq for &'a A where A: Eq + ?Sized

Note the where clause: it's implemented if and only if the thing behind the pointer can be compared for equality.

Your Node struct doesn't implement Eq, so it can't be compared for equality, thus pointers to it can't be compared for equality. Just whack a #[derive(Eq, PartialEq)] to the front of the structure to fix that.

Also note: pointers are compared based on the value being pointed to, not the pointer itself. i.e. Rust doesn't have "referential equality".

3 Likes

Well, references are compared that way. Raw pointers aren't:

struct T(u32); // no PartialEq/Eq implemented

fn main() {
    let a = T(1);
    let b = T(1);
    let p1 = &a;
    let p2 = &a;
    let p3 = &b;
    println!("{}", p1 as *const T == p2); // prints true
    println!("{}", p1 as *const T == p3); // prints false
}

If that's good style, I don't know.

1 Like

Ah, whoops. Thanks Daniel, I misread the signature. I do indeed want referential equality. Was going to cast to a size_t, but if a pointer works, that's even better (and more type-safe).

1 Like