Issue with borrow checker and returned references

I want to make an object that wraps a HashMap, similar to the example below:

use rand;
use rand::distributions::{Alphanumeric, DistString};
use std::collections::HashMap;

struct StringBank {
    strings: HashMap<usize, String>
}

impl StringBank {
    fn new() -> Self {
        StringBank {
            strings: HashMap::new()
        }
    }
    
    fn get_string_by_length(&mut self, length: usize) -> &str {
        match self.strings.get(&length) {
            Some(s) => &s,
            None => {
                let string = Alphanumeric.sample_string(&mut rand::thread_rng(), length);
                self.strings.insert(length, string);
                &self.strings.get(&length).unwrap()
            }
        }
    }
}

However, this example fails to compile because "cannot borrow 'self.strings' as mutable because it is also borrowed as immutable". I believe this problem is related to the fact that the returned reference can come from an immutable borrow from self.strings, and that borrow can live long enough for a potential mutable borrow of self.strings, but I don't understand how I can solve this.

(Note: I have no plans of making a remove_string_by_length, remake_string_by_length, or get_string_by_length_mut method, so the string that is returned should live as long as the StringBank and be immutable.)

It's a known NLL issue to be solved.

A fix here would be:

    fn get_string_by_length(&mut self, length: usize) -> &str {
        self.strings.entry(length).or_insert_with(|| {
            Alphanumeric.sample_string(&mut rand::thread_rng(), length)
        })
    }
1 Like

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.