gpt4 book ai didi

rust - 删除不可变借用以进行可变借用

转载 作者:行者123 更新时间:2023-11-29 07:56:40 25 4
gpt4 key购买 nike

我仍在学习 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 lifetimes现在启用,原始代码编译。话虽这么说,你仍然应该使用 entry API为了提高效率,否则你必须多次散列 key :

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);
}
}
}
}

在非词法生命周期之前

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

Explicit drops do not affect lifetimes .

let current_dist;
{
current_dist = dist.get(&state.node);
}

在这里,您没有在愚弄任何人。如果编译器对此感到困惑,那就不会很好了。这仍然借用了HashMap,只是散布了一些额外的 block 。

let current_dist = {|| dist.get(&state.node)}();

这里也一样。从闭包返回引用仍然是返回引用。你真的不能轻易地欺骗编译器认为你对 HashMap 的引用不存在。


您需要使用一个 block 来限制借用存在的时间。最简单的转换类似于:

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 调用不再隐含 panic 。

另见:

关于rust - 删除不可变借用以进行可变借用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42075409/

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