有没有办法区分相同值的不同`Rc`?

Is there a way to distinguish between different `Rc`s of the same value?

这是一个例子:

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);
}

以上两个 println! 打印 true。有没有办法区分 rc_a_*rc_b_* 指针?

您可以将 &*rc 转换为 *const T 以获得指向基础数据的指针并比较这些指针的值:

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
    );
}

打印

rc_a_0 == rc_a_1: true
rc_a_0 == rc_b_0: false

与 Dogbert 相同的答案,但可能更简洁一些:

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

简而言之,您想要引用相等,而不是值相等。原始指针的值是内存地址,所以比较原始指针的值相当于引用相等。

另请参阅:

2017稳定更新(2020年)。

在 Rust 1.17 及以后版本中,您可以使用 Rc::ptr_eq. It does the same as ptr::eq,无需将 Rc 转换为引用或指针。

参考平等

正如其他答案提到的 Rc::ptr_eq(和 ptr::eq)检查引用是否相等,即两个引用 "point" 是否指向同一地址。

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));

示例来自 Rust Rc::ptr_eq 文档。

价值观平等

Rc实现了PartialEq,所以只要一如既往地使用==来进行值相等,即值是否相等,与它们是否引用内存中的相同地址无关.

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);