删除不可变借用以进行可变借用
Drop a immutable borrow to make a mutable borrow
我仍在学习 Rust,在尝试将 Dikjstra 作为培训项目的一部分时,我遇到了这个奇怪的陷阱。首先我定义一个 HashMap
:
let mut dist: HashMap<Node, usize> = HashMap::new();
以后:
let state = State { node: next_node.clone(), cost: cost + 1 };
let current_dist = dist.get(&state.node);
if (current_dist == None) || (state.cost < *current_dist.unwrap()) {
dist.insert(state.node.clone(), state.cost);
heap.push(state);
}
这会产生一个编译错误,因为 dist.get
触发了一个不可变的借用,它一直在范围内,直到 if ... {...}
语句之后,特别是当我 dist.insert
请求可变借用时.
我想我错过了允许我进行此类过程的模式或关键字。现在,我在 if
范围的开头尝试了 drop
,以及其他 current_dist
评估,例如
let current_dist;
{
current_dist = dist.get(&state.node);
}
或
let current_dist = {|| dist.get(&state.node)}();
但不可变借用的范围结束仍然发生在 if
语句之后。
non-lexical 生命周期后
因为 non-lexical lifetimes are now enabled, the original code compiles. That being said, you should still use the entry API 为了效率,否则你必须多次散列密钥:
use std::collections::hash_map::Entry;
use std::collections::HashMap;
fn main() {
let mut dist: HashMap<u8, u8> = HashMap::new();
let cost = 21;
match dist.entry(42) {
Entry::Vacant(entry) => {
entry.insert(42);
}
Entry::Occupied(mut entry) => {
if *entry.get() < cost {
entry.insert(42);
}
}
}
}
non-lexical 生命周期之前
because dist.get
triggers a mutable borrow
没有,it's just an immutable borrow:
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq,
I tried a drop
。
let current_dist;
{
current_dist = dist.get(&state.node);
}
在这里你不是在愚弄任何人。如果编译器对此感到困惑,那就不会很好了。 仍然借用了HashMap
,只是散落了一些额外的方块。
let current_dist = {|| dist.get(&state.node)}();
这里也一样。从闭包返回引用仍然返回引用。你真的不能轻易欺骗编译器认为你对 HashMap
的引用不存在。
您需要使用一个块来限制借用存在的时间。最简单的转换类似于:
use std::collections::HashMap;
fn main() {
let mut dist: HashMap<u8, u8> = HashMap::new();
let do_it = {
let current_dist = dist.get(&42);
current_dist == None || true
};
if do_it {
dist.insert(42, 42);
}
}
这不是最漂亮的,但一些组合器可以清理它:
use std::collections::HashMap;
fn main() {
let mut dist: HashMap<u8, u8> = HashMap::new();
let cost = 21;
if dist.get(&42).map_or(true, |&val| val < cost) {
dist.insert(42, 42);
}
}
请注意,现在 unwrap
调用不再隐含恐慌。
另请参阅:
我仍在学习 Rust,在尝试将 Dikjstra 作为培训项目的一部分时,我遇到了这个奇怪的陷阱。首先我定义一个 HashMap
:
let mut dist: HashMap<Node, usize> = HashMap::new();
以后:
let state = State { node: next_node.clone(), cost: cost + 1 };
let current_dist = dist.get(&state.node);
if (current_dist == None) || (state.cost < *current_dist.unwrap()) {
dist.insert(state.node.clone(), state.cost);
heap.push(state);
}
这会产生一个编译错误,因为 dist.get
触发了一个不可变的借用,它一直在范围内,直到 if ... {...}
语句之后,特别是当我 dist.insert
请求可变借用时.
我想我错过了允许我进行此类过程的模式或关键字。现在,我在 if
范围的开头尝试了 drop
,以及其他 current_dist
评估,例如
let current_dist;
{
current_dist = dist.get(&state.node);
}
或
let current_dist = {|| dist.get(&state.node)}();
但不可变借用的范围结束仍然发生在 if
语句之后。
non-lexical 生命周期后
因为 non-lexical lifetimes are now enabled, the original code compiles. That being said, you should still use the entry API 为了效率,否则你必须多次散列密钥:
use std::collections::hash_map::Entry;
use std::collections::HashMap;
fn main() {
let mut dist: HashMap<u8, u8> = HashMap::new();
let cost = 21;
match dist.entry(42) {
Entry::Vacant(entry) => {
entry.insert(42);
}
Entry::Occupied(mut entry) => {
if *entry.get() < cost {
entry.insert(42);
}
}
}
}
non-lexical 生命周期之前
because
dist.get
triggers a mutable borrow
没有,it's just an immutable borrow:
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: Borrow<Q>,
Q: Hash + Eq,
I tried a
drop
let current_dist; { current_dist = dist.get(&state.node); }
在这里你不是在愚弄任何人。如果编译器对此感到困惑,那就不会很好了。 仍然借用了HashMap
,只是散落了一些额外的方块。
let current_dist = {|| dist.get(&state.node)}();
这里也一样。从闭包返回引用仍然返回引用。你真的不能轻易欺骗编译器认为你对 HashMap
的引用不存在。
您需要使用一个块来限制借用存在的时间。最简单的转换类似于:
use std::collections::HashMap;
fn main() {
let mut dist: HashMap<u8, u8> = HashMap::new();
let do_it = {
let current_dist = dist.get(&42);
current_dist == None || true
};
if do_it {
dist.insert(42, 42);
}
}
这不是最漂亮的,但一些组合器可以清理它:
use std::collections::HashMap;
fn main() {
let mut dist: HashMap<u8, u8> = HashMap::new();
let cost = 21;
if dist.get(&42).map_or(true, |&val| val < cost) {
dist.insert(42, 42);
}
}
请注意,现在 unwrap
调用不再隐含恐慌。
另请参阅: