简体   繁体   中英

Conflicting lifetime requirements when mapping mutable references with self

I am trying to write a method that, when given an array of keys for a HashMap, will return a Vec containing mutable references of the keys' corresponding values.

Here is the code:

struct Foo {
    bar: HashMap<u32, String>,
}

impl Foo {
    pub fn lookup(&mut self, keys: &[u32]) -> Vec<&mut String> {
        keys.iter()
            .filter(|&x| self.bar.contains_key(x))
            .map(|x| self.bar.get_mut(x).unwrap())
            .collect::<_>()
    }
}

This results in a conflicting lifetime error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:11:31
   |
11 |             .map(|x| self.bar.get_mut(x).unwrap())
   |                               ^^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 11:18...
  --> src/main.rs:11:18
   |
11 |             .map(|x| self.bar.get_mut(x).unwrap())
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `self`
  --> src/main.rs:11:22
   |
11 |             .map(|x| self.bar.get_mut(x).unwrap())
   |                      ^^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the method body at 8:5...
  --> src/main.rs:8:5
   |
8  | /     pub fn lookup(&mut self, keys: &[u32]) -> Vec<&mut String> {
9  | |         keys.iter()
10 | |             .filter(|&x| self.bar.contains_key(x))
11 | |             .map(|x| self.bar.get_mut(x).unwrap())
12 | |             .collect::<_>()
13 | |     }
   | |_____^
note: ...so that the expression is assignable
  --> src/main.rs:9:9
   |
9  | /         keys.iter()
10 | |             .filter(|&x| self.bar.contains_key(x))
11 | |             .map(|x| self.bar.get_mut(x).unwrap())
12 | |             .collect::<_>()
   | |___________________________^
   = note: expected  `std::vec::Vec<&mut std::string::String>`
              found  `std::vec::Vec<&mut std::string::String>`

Making an immutable version of the function works as intended, though I do not understand why:

pub fn lookup(&self, keys: &[u32]) -> Vec<&String> {
    keys.iter()
        .filter(|&x| self.bar.contains_key(x))
        .map(|x| self.bar.get(x).unwrap())
        .collect::<_>()
}

I am assuming this is a "fighting the borrow checker" issue, possibly due to self.bar being borrowed mutably multiple times. How would I go about fixing this?

The following works by filtering the values using the provided keys, rather than mapping the keys to their values. The code in the question, as SCappella correctly stated, would have lead to undefined behavior if duplicate valid keys were provided.

Working code:

pub fn lookup(&mut self, keys: &[u32]) -> Vec<&mut String> {
   self.bar.iter_mut().filter_map(|(k, v)| {
         if keys.contains(k) {
             Some(v)
         } else {
             None
         }
   }).collect::<_>()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM