gpt4 book ai didi

rust - 如何修改 HashSet 中不属于哈希计算的属性?

转载 作者:行者123 更新时间:2023-11-29 08:22:39 25 4
gpt4 key购买 nike

我有一个包含唯一 ID 并将该 ID 用于其哈希的结构:

use std::borrow::Borrow;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};

type Id = u32;

#[derive(Debug, Eq)]
struct Foo {
id: Id,
other_data: u32,
}

impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
self.id == other.id
}
}

impl Hash for Foo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}

impl Borrow<Id> for Foo {
fn borrow(&self) -> &Id {
&self.id
}
}

我明白,一旦我将 Foo::id 的值放入 HashSet 中,我就无法修改它,因为那样会更改散列。但是,我想修改 Foo::other_data。我知道我可以从 HashSet 中删除它,修改它,然后再次插入它,但是像 get_mut() 这样的方法会更干净。有没有办法完成这样的事情:

fn main() {
let mut baz = HashSet::new();
baz.insert(Foo {
id: 1,
other_data: 2,
});

if let Some(x) = baz.get_mut(&1) {
*x = 3;
}
}

这是反模式吗?我应该改用 HashMap 吗?

Related to this question.

最佳答案

这对于您当前的数据结构是不可能的。

HashSet 故意不提供改变值的方法。正如您所提到的,在大多数情况下,改变 HashSet 中的值(或 HashMap 中的键)会使散列无效。 API 鼓励正确使用,甚至提到了这一点:

It is a logic error for an item to be modified in such a way that the item's hash, as determined by the Hash trait, or its equality, as determined by the Eq trait, changes while it is in the set. This is normally only possible through Cell, RefCell, global state, I/O, or unsafe code.

这暗示了一种解决问题的方法,即使用内部可变性:

use std::cell::Cell;

#[derive(Debug, Eq)]
struct Foo {
id: Id,
other_data: Cell<u32>,
}
fn main() {
let mut baz = HashSet::new();
baz.insert(Foo {
id: 1,
other_data: Cell::new(2),
});

if let Some(x) = baz.get(&1) {
x.other_data.set(3);
}
}

这是一件合理的事情,但我不会为此感到兴奋。相反,我会允许将我的类型分解为一个键和一个值,并将其存储在 HashMap 中,如前所述。有点像


impl Foo {
// or insert_into_hashmap(self, &mut HashMap<Id, u32>)
fn into_key_value(self) -> (Id, u32) {
(self.id, self.other_data)
}

// Maybe a
//
// fn from_key_value(&'a Id, &'a u32) -> Self
// or
// fn from_hashmap(Id, &HashMap<Id, u32>) -> Self
}

// Maybe a
//
// struct FooRef<'a> { (or FooRefMut?)
// id: &'a Id,
// other_data: &'a u32,
// }
//
// With a
// fn from_key_value(&'a Id, &'a u32) -> Self
// or
// fn from_hashmap(Id, &HashMap<Id, u32>) -> Self

fn main() {
let mut baz = HashMap::new();
let f = Foo {
id: 1,
other_data: 2,
};
let (k, v) = f.into_key_value();
baz.insert(k, v);

// See also HashMap::get_key_value
if let Some(v) = baz.get_mut(&1) {
*v = 3;
}
}

关于rust - 如何修改 HashSet 中不属于哈希计算的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55464930/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com