Amigo
November 13, 2021, 3:00am
1
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
let v = get_or_insert(&mut map);
println!("{:?}", v);
}
fn get_or_insert(map: &mut HashMap<u32, String>) -> &String {
match map.get(&44) {
Some(v) => v,
None => {
map.insert(44, "value".to_string());
&map[&44]
}
}
}
(Playground )
Errors:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
--> src/main.rs:15:13
|
9 | fn get_or_insert(map: &mut HashMap<u32, String>) -> &String {
| - let's call the lifetime of this reference `'1`
10 |
11 | match map.get(&44) {
| --- immutable borrow occurs here
12 | Some(v) => v,
| - returning this value requires that `*map` is borrowed for `'1`
...
15 | map.insert(44, "value".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
Cyborus
November 13, 2021, 3:11am
2
I believe this is currently a limitation of the borrow checker. This should work, but doesn't yet.
Amigo
November 13, 2021, 3:13am
3
But why wont work. pls exapand this
Cyborus
November 13, 2021, 3:15am
4
When in the None
branch, it still thinks it has a reference to what map.get(&44)
returns, even though it doesn't.
Edit: Well, that's not quite right, but I think it's close.
The reference returned from get
isn't actually dropped until the end of the match expression, because it might be needed for the Some
case.
One option (which you probably already considered) is splitting the check in two.
if !map.contains_key(&44) {
map.insert(44, "value".to_string());
}
&map[&44]
This works because contains_key
returns a bool, which is a 'static
type, and thus no reference to map
is borrowed.
1 Like
Here's the bug for this not currently working.
You should use the Entry
API here. It avoids both the problem case and double-hashing.
fn get_or_insert(map: &mut HashMap<u32, String>) -> &String {
map.entry(44).or_insert_with(|| "value".to_string())
}
Playground.
9 Likes
kornel
November 15, 2021, 1:17am
7
That bug links to the exact explanation:
- Feature Name: (fill me in with a unique ident, my_awesome_feature)
- Start Date: (fill me in with today's date, YYYY-MM-DD)
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
# Summary
[summary]: #summary
Extend Rust's borrow system to support **non-lexical lifetimes** --
these are lifetimes that are based on the control-flow graph, rather
than lexical scopes. The RFC describes in detail how to infer these
new, more flexible regions, and also describes how to adjust our error
messages. The RFC also describes a few other extensions to the borrow
checker, the total effect of which is to eliminate many common cases
where small, function-local code modifications would be required to pass the
borrow check. (The appendix describes some of the remaining
borrow-checker limitations that are not addressed by this RFC.)
# Motivation
[motivation]: #motivation
This file has been truncated. show original
system
Closed
February 13, 2022, 1:17am
8
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.