Reputation: 45
In this:
#[derive(Debug)]
struct Person {
name: String,
}
fn main() {
let mut persons = Vec::<Person>::with_capacity(3);
let mut personrefs = Vec::<&Person>::with_capacity(persons.capacity());
for x in 0..persons.capacity() {
let person = Person {
name: format!("Alice-{}", x),
};
personrefs.push(&person);
persons.push(person);
}
println!("persons are {:#?}", persons);
}
I sort of understand why Rust wouldn't allow pushing &person
, but what is the Rust way of solving this?
I have a Vec
that "owns" Person
s, but I'd also like to map persons to some other data without touching the owning Vec
or duplicating Person
s in memory. Like, have a collections::HashMap<&Person, SomeOtherData>
. If both HashMap
and Vec
have the same lifetime, wouldn't Rust know when to deallocate Person
s?
Upvotes: 3
Views: 280
Reputation: 431489
The "Rust way" is the way that doesn't lead to memory unsafety. Your code is invalid, as the compiler tells you:
error[E0597]: `person` does not live long enough
--> src/main.rs:13:26
|
13 | personrefs.push(&person);
| ^^^^^^ borrowed value does not live long enough
14 | persons.push(person);
15 | }
| - `person` dropped here while still borrowed
16 | println!("persons are {:#?}", persons);
17 | }
| - borrowed value needs to live until here
You are creating a Person
inside the loop, taking a reference to it, then moving the Person
to a new memory address, invalidating the reference. If you accessed that reference, you'd be touching undefined memory, leading to segfaults at best or "strange behavior" / security vulnerabilities at worst.
Likewise, you can't add the person to the Vec
and then take a reference to that person in the loop because a subsequent iteration of the loop will mutate the vector. When you push to a vector, it might reallocate memory, again invalidating your references.
I'd write this code as
fn main() {
let persons: Vec<_> = (0..3)
.map(|x| Person {
name: format!("Alice-{}", x),
})
.collect();
let personrefs: Vec<_> = persons.iter().collect();
println!("persons are {:#?}", persons);
}
Upvotes: 5