如何在Rust HashMap中为同一键存储多个元素?

10

我有一个 HashMap<u32, Sender>。其中 Sender 是一个开放连接对象,而键是用户 ID。每个用户可以从多个设备连接。我需要存储相同用户 ID 的所有可能打开的连接。然后我可以迭代并向相同用户的所有打开连接发送消息。

上述的 HashMap 只存储每个用户 ID 和连接一次。我需要获得一个键对应多个值。如何将值转换为列表或数组,以便查看存在哪些连接并向它们全部发送?

我不是在谈论不同类型的值,比如枚举值。我指的是相同类型的值但超过一个。也许 HashMap 并不适用于此?

其他想法也可以。


4
那不是一个地图数据结构。你需要的是多值映射(multi-value map)或者是袋子(bag)。你试过用 HashMap<u32, Vec<Sender>> 这样的东西吗? - E net4
@E_net4,我对Vec不太熟悉(我是个初学者)。我在一些教程中看到过它们,但还没有完全理解。如果我理解的是正确的,你能否提供一个示例来详细说明一下,这样我就可以自己尝试了?顺便说一句,在设置后,我应该也能够添加/删除值。 - Dennis
3
您可以从《Rust编程语言》第8章 开始,该章节很好地介绍了使用Vec存储值列表的用法。标准库中没有多值映射集合类型,可能是因为它可以通过将映射与向量或集合相结合来实现。 - E net4
正在处理中。谢谢! - Dennis
1个回答

27

要使用HashMap实现这个功能,您应该将Vec用作值,以便每个键可以指向多个Sender。类型应为HashMap<u32,Vec<Sender>>

使用此结构,仅使用insert()在需要像这样改变值时可能会变得笨拙,但是相反,您可以使用Entry API来检索和更新记录。 例如:

let mut hash_map: HashMap<u32, Vec<Sender>> = HashMap::new();

hash_map.entry(3)
    // If there's no entry for key 3, create a new Vec and return a mutable ref to it
    .or_default()
    // and insert the item onto the Vec
    .push(sender); 

你还可以使用multimap crate,它在内部执行类似的操作,但添加了一层抽象。你可能会发现使用它更容易:

let mut multi_map = MultiMap::new();

multi_map.insert(3, sender_1);
multi_map.insert(3, sender_2);

multi_map.get(key)方法将返回第一个与该键匹配的值,而multi_map.get_vec(key)将检索所有匹配的值。


谢谢您提供的两个示例。我可以问一下如何删除特定的Vec(比方说,我想要删除其中一个Vec而不是整个条目)。我找不到合适的remove方法来删除值。 - Dennis
@Pratha 在这两种情况下,方法的名称都是相同的。只需执行 my_map.remove(key) 即可。 - Peter Hall
但是这会删除所有值的键,我对吗?我想保留键和值,但删除其中一个值。 - Dennis
@Pratha 好的,你不想删除Vec,只是其中的一个元素?在上面的代码中,.entry(key).or_insert_with(Vec::new) 会给你一个可变的 Vec 引用。如果你选择使用 MultiMap,那么 .get_vec_mut(key) 也会给你同样的东西。在这两种情况下,你都会得到一个可变的 Vec 引用,所以你可以使用任何 Vec 方法 来完成你需要做的事情。如果你仍然有问题,我建议你花一点时间熟悉 Vec,如果真的卡住了,可能要问一个新问题。 - Peter Hall
没错,这个方法可行。你解释得非常好,再次感谢。我一定会学习Vec的。 - Dennis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接