rustimmutabilityborrow-checkerborrowing

Can I get a value from an immutable BTreeMap?


The below two code blocks are meant to be equivalent, but for some reason I get a compiler error on the second.

I'm having a hard time understanding why names is borrowed in one version, versus the other.

I have tried to work out how to read from an immutable BTreeMap, but there doesn't seem to be a clear way.

Works fine:

let region_name: Option<String> = match subdivision.to_owned() {
    Some(division) => match division.names.unwrap().get("en") {
        Some(name) => Some(name.to_string()),
        _ => None,
    },
    _ => None,
};

Does not compile:

let region_name: Option<String> = subdivision
    .to_owned()
    .and_then(|division|division.names)
    .and_then(|names| names.get("en"))
    .and_then(|name| Some(name.to_string()));

Compiler message:

error[E0515]: cannot return value referencing function parameter `names`
  --> src/lib.rs:82:27
   |
82 |         .and_then(|names| names.get("en"))
   |                           -----^^^^^^^^^^
   |                           |
   |                           returns a value referencing data owned by the current function
   |                           `names` is borrowed here

subdivision is the following:

#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct Subdivision<'a> {
    pub geoname_id: Option<u32>,
    pub iso_code: Option<&'a str>,
    pub names: Option<BTreeMap<&'a str, &'a str>>,
}

Solution

  • .and_then(|names| names.get("en"))
    

    names are dropped at the end of the function (or closure) but you are trying to return names.get("en"), which has a reference to the value in names (Option<&&str>).

    .and_then(|data| data.get("en").map(|s| s.to_string()))
    

    This code may work.