在结构上实现的最简单方法是什么Hash/Eq,以便具有相同属性的两个不同实例不相等?
考虑以下结构:
struct Person {
name: String,
}
Run Code Online (Sandbox Code Playgroud)
Hash/Eq即使两个不同的人具有相同的名字,最简单的实现方法是什么?是某件事的唯一途径Box<>吗?
你不知道。Rust 不是 Java。两个相同的Person实例在内存中由完全相同的位序列表示,因此无法区分。甚至Box不会在这里保存您:委托所包含值的实例EqBox。
按照您描述的方式比较指针相等性的唯一方法是使用std::ptr::eq, usingstd::pin确保指针不会更改。但是,我必须强调这一点,这是错误的做法。你不想要这种平等。这在 Rust 中没有意义。如果Person { name: "Joe" }和Person { name: "Joe" }是不同的对象,那么您的数据结构设计得很糟糕。您的工作就是添加一个区分字段。如果这些由数据库支持,您可以使用
struct Person {
primary_key: u64,
name: String,
}
Run Code Online (Sandbox Code Playgroud)
或者也许每个人都有一个十六进制的员工 ID。
struct Person {
employee_id: String,
name: String,
}
Run Code Online (Sandbox Code Playgroud)
关键是数据结构本身(Person在我们的示例中)对它的所有内容进行了编码。Rust 避开了 Java 式的概念,即每个对象本质上都具有与所有其他对象不同的身份,而有利于数据向世界明确地描述自身。
正如 @SilvioMayolo 所指出的,值“身份”在 Rust 中不是一个东西,因为 Rust 的值默认不是堆分配的。虽然您可以获取任何值的地址,但不能使用它来表示身份,每次将值移动到不同的变量、传递给函数或插入到容器中时,地址都会发生变化。您可以通过堆分配值来使地址稳定,但这需要在创建值时进行分配,并在每次访问时进行额外的取消引用。
对于堆分配其内容的值(例如Strings),您可以使用内容的地址来表示身份,如 @Smitop 的答案所示。但这也不是身份的良好表示,因为它会在字符串重新分配时随时发生变化,例如,如果您向其中附加一些数据。如果您从不打算增加琴弦,那么这个选项会很有效。否则,您必须使用其他东西。
一般来说,您可以显式地跟踪作为对象一部分的身份,而不是使用地址来表示身份。没有什么可以阻止您添加表示身份的字段,并在构造函数中分配它:
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
pub struct Person {
id: u64,
name: String,
}
impl Person {
/// Create a new unique person.
pub fn new(name: String) -> Self {
Person {
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
name,
}
}
/// Identity of a `Person`.
///
/// Two persons with the same name will still have different identities.
pub fn id(&self) -> u64 {
self.id
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以实现Hash并Eq使用这个身份:
impl Hash for Person {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Eq for Person {}
impl PartialEq for Person {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
// We can't #[derive(Clone)] because that would clone the id, and we
// want to generate a new one instead.
impl Clone for Person {
fn clone(&self) -> Person {
Person::new(self.name.clone())
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1676 次 |
| 最近记录: |