Like any good farmer, Rust is my programming language of choice. But these darn Cows keep wandering into the field over and mixing with the neighbour's herd, and next thing you know, you can't tell who owns what. Will you help out an honest farmer?
The following compiles.
struct Foo<'a> {
item: Cow<'a, str>,
}
fn experiment<'a>(foos: &'a [Foo<'a>]) -> Vec<&'a str> {
let mut strings: Vec<&'a str> = vec![];
for f in foos {
let thing: &'a str = &f.item;
strings.push(thing);
}
strings
}
We're iterating through a borrowed structure whose elments contain a Cow
. Regardless of the internal ownership status of the innards of the Cow
(either a &str
it got from somewhere else, or an owned String
it had to clone at some point), we're able to copy all those references into a new container (Vec
here) and give it back. No ownership has transferred, it's just like we're "stripping off" the Cowness.
Alright, let's try a HashMap
instead:
fn experiment_2<'a>(foos: &'a [Foo<'a>]) -> HashMap<&'a str, &'a str> {
let mut strings: HashMap<&'a str, &'a str> = HashMap::new();
for f in foos {
let thing: &'a str = &f.item;
strings.insert(thing, thing);
}
strings
}
This compiles too. So far so good. One little tweak and we can break it:
fn experiment_3<'a>(foos: &'a mut [Foo<'a>]) -> HashMap<&'a str, &'a str> {
let mut strings: HashMap<&'a str, &'a str> = HashMap::new();
for i in 0..foos.len() {
match foos.get_mut(i) {
Some(f) => {
let thing: &'a str = &f.item;
strings.insert(thing, thing);
}
None => {}
}
}
strings
}
Calling get_mut
here gives us the dreaded:
*foos
was mutably borrowed here in the previous iteration of the loop
I've read elsewhere about why this is, and mostly understand. Rust wants to know that I'm not mutably borrowing the same index more than once. But actually, why should Rust care? What if I want to borrow the same index more than once? In the code above that won't happen, but in my real-world scenario that's precisely where I find myself.
Furthermore, getting rid of the Cow
but leaving the other code the same gets rid of the error:
struct Bar<'a> {
item: &'a str,
}
fn experiment_4<'a>(bars: &'a mut [Bar<'a>]) -> HashMap<&'a str, &'a str> {
let mut strings: HashMap<&'a str, &'a str> = HashMap::new();
for i in 0..bars.len() {
match bars.get_mut(i) {
Some(f) => {
let thing: &'a str = &f.item;
strings.insert(thing, thing);
}
None => {}
}
}
strings
}
This compiles just fine. Why? What about Cow
-nature makes Rust mad in the penultimate case, but not the final? Yes get
and not get_mut
doesn't suffer from this, but in my real-world case I need get_mut
. Any idea what's going on?
Thank you kindly.