11

Here's an example:

use std::rc::Rc;

#[derive(PartialEq, Eq)]
struct MyId;

pub fn main() {
    let rc_a_0 = Rc::new(MyId);
    let rc_a_1 = rc_a_0.clone();
    let rc_b_0 = Rc::new(MyId);
    let rc_b_1 = rc_b_0.clone();

    println!("rc_a_0 == rc_a_1: {:?}", rc_a_0 == rc_a_1);
    println!("rc_a_0 == rc_b_0: {:?}", rc_a_0 == rc_b_0);
}

Both println!s above print true. Is there a way distinguish between the rc_a_* and rc_b_* pointers?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ynimous
  • 4,642
  • 6
  • 27
  • 43

3 Answers3

25

2017 stabilization update (in 2020).

In Rust 1.17 and forward, you can use Rc::ptr_eq. It does the same as ptr::eq, without the need of converting the Rc to a reference or pointer.

Reference Equality

As the other answers mention Rc::ptr_eq (and ptr::eq) checks for reference equality, i.e. whether the two references "point" to the same address.

let five = Rc::new(5);
let same_five = Rc::clone(&five);
let other_five = Rc::new(5);

// five and same_five reference the same value in memory
assert!(Rc::ptr_eq(&five, &same_five));

// five and other_five does not reference the same value in memory
assert!(!Rc::ptr_eq(&five, &other_five));

The example is from the Rust Rc::ptr_eq docs.

Value Equality

Rc implements PartialEq, so simply use == as always, to perform value equality, i.e. whether the values are equal, irrelevant of whether they reference the same address in memory.

use std::rc::Rc;

let five = Rc::new(5);
let other_five = Rc::new(5);

let ten = Rc::new(10);

assert!(five == other_five);

assert!(ten != five);
assert!(ten != other_five);
vallentin
  • 23,478
  • 6
  • 59
  • 81
8

You can cast &*rc to *const T to get a pointer to the underlying data and compare the value of those pointers:

use std::rc::Rc;

#[derive(PartialEq, Eq)]
struct MyId;

pub fn main() {
    let rc_a_0 = Rc::new(MyId);
    let rc_a_1 = rc_a_0.clone();
    let rc_b_0 = Rc::new(MyId);
    let rc_b_1 = rc_b_0.clone();

    println!(
        "rc_a_0 == rc_a_1: {:?}",
        &*rc_a_0 as *const MyId == &*rc_a_1 as *const MyId
    );
    println!(
        "rc_a_0 == rc_b_0: {:?}",
        &*rc_a_0 as *const MyId == &*rc_b_0 as *const MyId
    );
}

prints

rc_a_0 == rc_a_1: true
rc_a_0 == rc_b_0: false
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Dogbert
  • 212,659
  • 41
  • 396
  • 397
7

The same answer as Dogbert, but maybe a bit cleaner:

use std::ptr;

println!(
    "rc_a_0 == rc_a_1: {:?}",
    ptr::eq(rc_a_0.as_ref(), rc_a_1.as_ref())
);
println!(
    "rc_a_0 == rc_b_0: {:?}",
    ptr::eq(rc_a_0.as_ref(), rc_b_0.as_ref())
);
rc_a_0 == rc_a_1: true
rc_a_0 == rc_b_0: false

In short, you want reference equality, not value equality. A raw pointer's value is the memory address, so comparing the value of a raw pointer is equivalent to reference equality.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • 3
    For comparing pointers, it is probably good practice to always cast to `*const MyType` first, or at least specify the type in `ptr::eq::(...)`. Otherwise, you might be comparing the wrong type (e.g. `&&MyType` instead of `&MyType`, or `Deref`ed values). – SOFe Aug 01 '20 at 05:31