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>>,
}
.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.