Rust 从HashMap或Vec返回引用会导致借用持续时间超出其作用域';她在吗?
我遇到了一个持久的编译错误,Rust抱怨我在尝试可变借用时有一个不可变的借用,但是不可变的借用来自另一个范围,我没有从中带来任何东西 我有一些代码检查映射中的值,如果它存在,则返回它,否则它需要以各种方式改变映射。问题是我似乎找不到一种方法来除锈,让我两者都做吧,即使这两个操作是完全分开的 下面是一些与我的代码结构相同的无意义代码,并显示了问题:Rust 从HashMap或Vec返回引用会导致借用持续时间超出其作用域';她在吗?,rust,borrow-checker,Rust,Borrow Checker,我遇到了一个持久的编译错误,Rust抱怨我在尝试可变借用时有一个不可变的借用,但是不可变的借用来自另一个范围,我没有从中带来任何东西 我有一些代码检查映射中的值,如果它存在,则返回它,否则它需要以各种方式改变映射。问题是我似乎找不到一种方法来除锈,让我两者都做吧,即使这两个操作是完全分开的 下面是一些与我的代码结构相同的无意义代码,并显示了问题: use std::collections::BTreeMap; fn do_stuff(map: &mut BTreeMap<i32,
use std::collections::BTreeMap;
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
// extra scope in vain attempt to contain the borrow
{
// borrow immutably
if let Some(key) = map.get(&key) {
return Some(key);
}
}
// now I'm DONE with the immutable borrow, but rustc still thinks it's borrowed
map.insert(0, 0); // borrow mutably, which errors
None
}
使用std::collections::BTreeMap;
fn do_stuff(映射:&mutbtreemap,键:i32)->选项{
//额外作用域徒劳地试图包含借用
{
//一成不变地借钱
如果let Some(key)=map.get(&key){
返回一些(键);
}
}
//现在我已经完成了不可变的借用,但rustc仍然认为它是借用的
map.insert(0,0);//可变借用,哪个错误
没有一个
}
此错误与以下内容有关:
error[E0502]:无法将“*map”作为可变项借用,因为它也是作为不可变项借用的
-->src/lib.rs:14:5
|
3 | fn do_stuff(映射:&mutbtreemap,键:i32)->选项{
|-我们将此引用的生存期称为“1”`
...
7 |如果让一些(键)=映射。获取(&key){
|---此处发生不可变借用
8 |返回一些(键);
|------返回此值需要为“%1”借用“*map”`
...
14 | map.insert(0,0);//可变借用,哪个错误
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^此处发生可变借用
这对我来说没有任何意义。不可变的借词如何超过该范围?!该match
的一个分支通过return
退出函数,而另一个分支什么也不做并离开该范围
我以前见过这种情况,在其他变量中,我错误地将借来的数据带出了作用域,但这里的情况并非如此
的确,借用是通过return
语句逃出作用域的,但在函数中阻止进一步借用是荒谬的——程序不可能返回并继续运行!如果我在那里返回其他内容,错误就会消失,因此我想这就是借用检查器遇到的问题。这感觉像是一个错误虫子对我来说
不幸的是,我一直无法找到任何方法来重写它而不出现相同的错误,因此如果是这样的话,这是一个特别严重的错误。这是一个将在的未来迭代中解决的问题,但目前未在Rust 1.51中处理
如果您正在插入正在查找的同一个键,我建议您改为插入
你现在可以添加一点低效率来解决这个问题。如果低效率是不可接受的
HashMap
一般的想法是添加一个布尔值,告诉您是否存在值。此布尔值不挂起引用,因此不存在借用:
use std::collections::BTreeMap;
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
if map.contains_key(&key) {
return map.get(&key);
}
map.insert(0, 0);
None
}
fn main() {
let mut map = BTreeMap::new();
do_stuff(&mut map, 42);
println!("{:?}", map)
}
你可以写:
fn find_or_create_five<'a>(container: &'a mut Vec<u8>) -> &'a mut u8 {
let idx = container.iter().position(|&e| e == 5).unwrap_or_else(|| {
container.push(5);
container.len() - 1
});
&mut container[idx]
}
fn查找或创建五个(容器:&mut Vec)->&mut u8{
匹配container.iter_mut().find(| e |**e==5){
一些(元素)=>元素,
无=>{
容器。推(5);
container.last_mut().unwrap()
}
}
}
另见:
- 这是同样的问题,但不返回引用,它与Rust 1.32中提供的NLL实现一起工作
- 这是一个比较复杂的问题
- 终极逃生舱
fn find_or_create_five<'a>(container: &'a mut Vec<u8>) -> &'a mut u8 {
let idx = container.iter().position(|&e| e == 5).unwrap_or_else(|| {
container.push(5);
container.len() - 1
});
&mut container[idx]
}
use std::collections::BTreeMap;
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
if let Some(key) = map.get(&key) {
return Some(key);
}
map.insert(0, 0);
None
}
fn find_or_create_five(container: &mut Vec<u8>) -> &mut u8 {
match container.iter_mut().find(|e| **e == 5) {
Some(element) => element,
None => {
container.push(5);
container.last_mut().unwrap()
}
}
}