Search code examples
iteratorrustlifetimeborrow-checkermutability

How to extract values from &mut iterator?


I am trying to make an iterator that maps a string to an integer:

fn main() {
    use std::collections::HashMap;

    let mut word_map = HashMap::new();

    word_map.insert("world!", 0u32);

    let sentence: Vec<&str> = vec!["Hello", "world!"];

    let int_sentence: Vec<u32> = sentence.into_iter()
        .map(|x| word_map.entry(x).or_insert(word_map.len() as u32))
        .collect();

}

(Rust playground)

This fails with

the trait core::iter::FromIterator<&mut u32> is not implemented for the type collections::vec::Vec<u32>

Adding a dereference operator around the word_map.entry().or_insert() expression does not work as it complains about borrowing which is surprising to me as I'm just trying to copy the value.


Solution

  • The borrow checker uses lexical lifetime rules, so you can't have conflicting borrows in a single expression. The solution is to extract getting the length into a separate let statement:

    let int_sentence: Vec<u32> = sentence.into_iter()
            .map(|x| *({let len = word_map.len() as u32;
                        word_map.entry(x).or_insert(len)}))
            .collect();
    

    Such issues will hopefully go away when Rust supports non-lexical lifetimes.