I've created a stripped down example of a problem I've been having when trying to get a mutable reference to an item in a HashMap inside a closure. If I understand correctly, the lifetime of each entry in the HashMap should be linked to the lifetime of the HashMap, so I'm not sure why it is complaining about the different lifetimes. If anyone could shed some light on this I would be very grateful. As I've said, this is a very stripped down version, and I'm aware that in this example it doesn't actually need to return a mutable reference, but in my actual use case it does.
Your function copied here for reference:
pub fn get<'a>(items: &'a mut HashMap<u32, String>) -> Option<&'a mut String> {
(1..5).find_map(|n| items.get_mut(&n))
}
For that closure to return the full lifetime &'a mut
, it would have to consume the source &'a mut
reference entirely. The find_map
closure can't do that though, as it will be called multiple times -- it's not FnOnce
. There's no way to tell the compiler that once it returns an actual borrow, Some(&'a mut T)
, that it should never be called again.
You could open-code that loop something like this:
pub fn get<'a>(items: &'a mut HashMap<u32, String>) -> Option<&'a mut String> {
for n in 1..5 {
if let Some(s) = items.get_mut(&n) {
return Some(s);
}
}
None
}
This almost works, but still runs into a limitation of the borrow checker, even with NLL:
error[E0499]: cannot borrow `*items` as mutable more than once at a time
--> <source>:5:26
|
3 | pub fn get<'a>(items: &'a mut HashMap<u32, String>) -> Option<&'a mut String> {
| -- lifetime `'a` defined here
4 | for n in 1..5 {
5 | if let Some(s) = items.get_mut(&n) {
| ^^^^^ mutable borrow starts here in previous iteration of loop
6 | return Some(s);
| ------- returning this value requires that `*items` is borrowed for `'a`
There's an even newer borrow checker that you can enable on nightly with -Zpolonius
, and then this code would be accepted.
If instead you accept a double-lookup between checking if the value exists, then retrieving the mutable reference, you can write it like this even on stable rust:
pub fn get<'a>(items: &'a mut HashMap<u32, String>) -> Option<&'a mut String> {
let n = (1..5).find(|n| items.contains_key(n))?;
items.get_mut(&n)
}
Hopefully you can translate some pattern from this example to your actual use case!
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.