我可以可变地借用哈希映射条目,而哈希映射本身是不可改变地借用的吗?

问题描述 投票:0回答:1

我正在尝试迭代哈希图,并根据每个条目的内容,对“不同”条目进行更改。重要的是我永远不要更改我正在查看的条目。我认为这使得算法安全,但我似乎无法说服 Rust 相信这一事实。

HashMap::get_mut

的文档说“返回对与键对应的

value
的可变引用”,但错误消息表明它正在尝试锁定哈希图本身: type Hash = String; type Hashes = Vec<Hash>; ... struct RawNode { parents : Hashes, children : Hashes, ... fn make_bi() -> HashMap<Hash, RawNode> { let raw_graph = make_raw(); // Reads stdin to make a map of commits with parents known. // We want to populate the children of each commit. for (h, n) in raw_graph.iter() { for ph in n.parents.iter() { if let Some(p) = raw_graph.get_mut(ph) { p.children.push(h.to_string()); } } } raw_graph } || cannot borrow `raw_graph` as mutable because it is also borrowed as immutable || | || 77 | for (h, n) in raw_graph.iter() { || | ---------------- || | | || | immutable borrow occurs here || | immutable borrow later used here || 78 | for ph in n.parents.iter() { || 79 | if let Some(p) = raw_graph.get_mut(ph) { || | ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here ||

也许这意味着第一个不可变的借用捕获了其网络中的所有条目 - 文档没有指定,但肯定这不是迭代集合所必需的。当迭代实际上返回一个特定条目时,显然该条目会被锁定,但没有理由同时锁定其他条目。

我看到这个问题:

Rust:修改 HashMap 中的值,同时不可变地借用整个 HashMap

但是该作者试图同时阅读和编写给定的条目,所以我怀疑那里的建议对于我的目的来说是多余的。它还涉及昂贵的克隆,就我而言,我认为没有必要。

那么我误解了什么?我该如何绕过它而不造成丑陋或浪费?

rust hashmap borrow-checker
1个回答
0
投票
也许这意味着第一个不可变的借用捕获了其网络中的所有条目 - 文档没有指定,但肯定这不是迭代集合所必需的。

实际上是这样的:虽然现在这是可能的(尽管不是微不足道的),但直到最近,Rust 的类型系统还无法表达“借用迭代”,即项目仅在循环体期间有效的迭代。相反,Rust 的迭代要求迭代器在整个迭代及之后都有效,例如

let mut it = raw_graph.iter(); let i1 = it.next(); let i2 = it.next(); let i3 = it.next();

必须是合法的。

请注意,这与本例无关。

当迭代实际返回一个特定条目时,显然该条目会被锁定,但没有理由同时锁定其他条目。

您正在动态推理,但借用检查器是静态的,它无法知道
ph

的条目在所有情况下都与

n
不同(即使是这种情况)。因此,获得对值的可变引用
需要
获得对集合的可变引用以确保不会出现别名,因此HashMap::get_mut的签名在主题上是明确的:
fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>

您可以通过
内部可变性

进行“动态借用检查”,例如在你的值周围加上 RefCell 可以让你通过共享引用改变底层值(运行时检查后)。

您也可以尝试使用并发映射,尽管这可能会使问题变得更糟,例如虽然 

dashmap

允许从共享引用获取可变子引用,但如果同一线程持有对同一

shard
的未完成引用(用于管理并发访问的内部块),则会发生死锁。

© www.soinside.com 2019 - 2024. All rights reserved.