Closed as not planned
Description
I tried this code:
use std::collections::HashMap;
pub fn find<'a>(lookup: &HashMap<u32, usize>, items: &'a mut Vec<u32>, id: u32) -> Option<&'a mut u32> {
if let Some(token) = lookup.get(&id) {
return items.get_mut(*token);
}
if let Some(token) = lookup.get(&id.wrapping_add(1)) {
let item = items.get_mut(*token)?;
if *item == id {
return Some(item);
}
}
if let Some(token) = lookup.get(&(id.wrapping_sub(1))) {
let item = items.get_mut(*token)?;
if *item == id {
return Some(item);
}
}
None
}
I expected to see this happen: Code should compile because the latter get_mut
calls don't overlap with preceding ones.
Instead, this happened: Got following error
error[E0499]: cannot borrow `*items` as mutable more than once at a time
--> src/lib.rs:16:20
|
3 | pub fn find<'a>(lookup: &HashMap<u32, usize>, items: &'a mut Vec<u32>, id: u32) -> Option<&'a mut u32> {
| -- lifetime `'a` defined here
...
9 | let item = items.get_mut(*token)?;
| ----- first mutable borrow occurs here
10 | if *item == id {
11 | return Some(item);
| ---------- returning this value requires that `*items` is borrowed for `'a`
...
16 | let item = items.get_mut(*token)?;
| ^^^^^ second mutable borrow occurs here
It works if I comment the if condition inside the second if let
:
use std::collections::HashMap;
pub fn find<'a>(lookup: &HashMap<u32, usize>, items: &'a mut Vec<u32>, id: u32) -> Option<&'a mut u32> {
if let Some(token) = lookup.get(&id) {
return items.get_mut(*token);
}
if let Some(token) = lookup.get(&id.wrapping_add(1)) {
let item = items.get_mut(*token)?;
// if *item == id {
return Some(item);
// }
}
if let Some(token) = lookup.get(&(id.wrapping_sub(1))) {
let item = items.get_mut(*token)?;
if *item == id {
return Some(item);
}
}
None
}
if I comment the last if let
, then also it works:
use std::collections::HashMap;
pub fn find<'a>(lookup: &HashMap<u32, usize>, items: &'a mut Vec<u32>, id: u32) -> Option<&'a mut u32> {
if let Some(token) = lookup.get(&id) {
return items.get_mut(*token);
}
if let Some(token) = lookup.get(&id.wrapping_add(1)) {
let item = items.get_mut(*token)?;
if *item == id {
return Some(item);
}
}
// if let Some(token) = lookup.get(&(id.wrapping_sub(1))) {
// let item = items.get_mut(*token)?;
// if *item == id {
// return Some(item);
// }
// }
None
}
So there are still multiple mutable borrows but it works for those cases. But why not in the first case? Is it incorrect borrowing pattern somehow that I am not seeing?
Meta
rustc --version --verbose
:
rustc 1.46.0-nightly (346aec9b0 2020-07-11)
binary: rustc
commit-hash: 346aec9b02f3c74f3fce97fd6bda24709d220e49
commit-date: 2020-07-11
host: x86_64-unknown-linux-gnu
release: 1.46.0-nightly
LLVM version: 10.0
Thanks