I am trying to construct a bunch of linked-list data-structure in Rust, but different than other examples I've seen, I'd like the actual nodes to be owned by a HashMap. It seems like if a HashMap owns the nodes, then lifetimes shouldn't be an issue and this should allow me to reference the next element in my list by Option<&List> rather than Box<List> (as done in Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time ). However, I am getting mutable/immutable borrow errors.
My minimal example is:
use std::collections::HashMap;
#[derive(Debug, Default)]
struct List<'a> {
data: i32,
child: Option<&'a List<'a>>,
}
fn main() {
let mut map = HashMap::<i32, List>::new();
let data = vec![(1, None), (2, Some(1))];
for (data, child) in data.iter() {
println!("Inserting {:?} with child {:?}", data, child);
let new_node = map.entry(*data).or_insert(List {
data: *data,
child: None,
});
match child {
Some(child_data) => {
map.get(child_data).map(|child_node| {
new_node.child = Some(child_node);
});
}
None => {}
}
}
println!("Data: {:?}", map);
}
Which gives the error
error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable
--> src/main.rs:16:24
|
16 | let new_node = map.entry(*data).or_insert(List {
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
22 | map.get(child_data).map(|child_node| {
| --- immutable borrow occurs here
error[E0502]: cannot borrow `map` as immutable because it is also borrowed as mutable
--> src/main.rs:22:17
|
16 | let new_node = map.entry(*data).or_insert(List {
| --- mutable borrow occurs here
...
22 | map.get(child_data).map(|child_node| {
| ^^^ immutable borrow occurs here
23 | new_node.child = Some(child_node);
| -------- mutable borrow later captured here by closure
My question is, is this error a result of me not setting up the List struct correctly, a result of the way I am using HashMap, and how can I fix it?
The error is correct:
If you have a node that refers to itself (e.g. (1, Some(1))), then new_node and child_node will point to the same value. This is illegal as new_node is a mutable (read: exclusive) reference.
HashMap, like Vec, is backed by an array. When the HashMap fills up, it will reallocate this array, invalidating all existing references.
HashMap lets you delete entries. This will cause dangling pointers if a deleted entry is referenced elsewhere.
Here are a few solutions to this problem:
Store the index instead. This is the simplest solution, and is recommended most of the time.
struct List {
data: i32,
child: Option<i32>,
}
Use an append-only collection like elsa::FrozenMap. This only solves problem 3, but Box and Cell should handle the rest:
use elsa::FrozenMap;
struct List<'a> {
data: i32,
child: Cell<Option<&'a List<'a>>>,
}
fn main() {
let map = FrozenMap::<i32, Box<List>>::new();
// ...
}
Related
I'm attempting to store a reference to an element of a mutable vector to use later. However, once I mutate the vector, I can no longer use the stored reference. I understand that this is because borrowing reference to the element also requires borrowing a reference to the vector itself. Therefore, the vector cannot be modified, because that would require borrowing a mutable reference, which is disallowed when another reference to the vector is already borrowed.
Here's a simple example
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Person> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| Person {
name: s.to_string(),
})
.collect();
// Borrow a reference to an element
let person_ref = &people[0];
// Mutate the vector
let new_person = Person {
name: "Tim".to_string(),
};
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}
which produces the following error
error[E0502]: cannot borrow `people` as mutable because it is also borrowed as immutable
--> src/main.rs:21:5
|
15 | let person_ref = &people[0];
| ------ immutable borrow occurs here
...
21 | people.push(new_person);
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
24 | assert!(person_ref.name == "Joe");
| --------------- immutable borrow later used here
I've also tried boxing the vector elements as suggested here, but that doesn't help. I thought it might allow me to drop the reference to the vector while maintaining a reference to the element, but apparently not.
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Box<Person>> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| {
Box::new(Person {
name: s.to_string(),
})
})
.collect();
// Borrow a reference to an element
let person_ref = people[0].as_ref();
// Mutate the vector
let new_person = Box::new(Person {
name: "Tim".to_string(),
});
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}
This still produces the same error
error[E0502]: cannot borrow `people` as mutable because it is also borrowed as immutable
--> src/main.rs:23:5
|
17 | let person_ref = people[0].as_ref();
| ------ immutable borrow occurs here
...
23 | people.push(new_person);
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
26 | assert!(person_ref.name == "Joe");
| --------------- immutable borrow later used here
Is there a way to do this, or am I trying to do something impossible?
I found that using a reference counted smart pointer allows me to accomplish what I'm attempting. It makes sense that a shared ownership is necessary, because otherwise the element reference would become invalid if the original vector were to go out of scope (which would deallocate the element, with or without the Box).
The following code compiles successfully.
use std::rc::Rc;
struct Person {
name: String,
}
fn main() {
// Create a mutable vector
let mut people: Vec<Rc<Person>> = ["Joe", "Shavawn", "Katie"]
.iter()
.map(|&s| {
Rc::new(Person {
name: s.to_string(),
})
})
.collect();
// Borrow a reference to an element
let person_ref = Rc::clone(&people[0]);
// Mutate the vector
let new_person = Rc::new(Person {
name: "Tim".to_string(),
});
people.push(new_person);
// Attempt to use the borrowed reference
assert!(person_ref.name == "Joe");
}
If anyone else has any corrections, improvements or further insight, I'd be glad to hear it. But if not, I feel satisfied with this answer for now.
I'm trying to call a mutable method inside a immutable scope with gives me: error[E0502].
I'm already understand why this error occurs but I'm struggle on how to fix it or how to do a different approach that works.
Here a MCVE
struct A {
list: Vec<i8>,
has_three: bool,
}
impl A {
pub fn new() -> Self {
Self {
list: vec![1,2,3],
has_three: false,
}
}
pub fn mutable_method(&mut self) {
for item in self.list.iter() {
self.mutable_method2(item);
}
}
fn mutable_method2(&mut self, item: &i8) {
let b: i8 = 3;
if item == &b {
self.has_three = true;
}
}
}
fn main() {
let mut a = A::new();
a.mutable_method();
}
And the Error received:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:13
|
14 | for item in self.list.iter() {
| ----------------
| |
| immutable borrow occurs here
| immutable borrow later used here
15 | self.mutable_method2(item);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
You asked for another approach. If I correctly assume that your goal is to have has_three be true if any entry is 3, that's much more easily done this way:
pub fn mutable_method(&mut self) {
self.has_three = self.list.iter().any(|&x| x == 3);
}
By the way, you need to make sure mutable_method is actually called appropriately, otherwise you will end up in logically invalid states. That's not good practice. Consider extracting this to the constructing function already.
Some background
The underlying problem is that your initial approach wants to borrow self mutably, while already borrowing it immutably. However, logically, your code is not obviously invalid, as you only borrow a part of the struct mutably that you do not also borrow immutably. This information is lost though.
We make the safety explicit by factoring into two implicit operations,
let tmp = self.list.iter().any(|&x| x == 3);
self.has_three = tmp;
which both operate on the struct in a 'clear fashion', either mutably or immutably. That is how you can approach such problems.
I am stuck on the borrow checker.
pub struct Gamepad {
str: String,
}
pub enum Player {
Human(Gamepad),
Computer,
}
pub struct PlayerData {
pub player: Player, /* actually this should be private */
}
struct Pong {
players: Vec<PlayerData>,
}
fn update_game(_pong: &mut Pong) {}
fn main() {
println!("Hello, world!");
let mut pong = Pong {
players: vec![
PlayerData {
player: Player::Computer,
},
PlayerData {
player: Player::Human(Gamepad {
str: "mydev".to_string(),
}),
},
],
};
game_loop(&mut pong);
}
fn game_loop(pong: &mut Pong) {
let mut vec: Vec<&Gamepad> = Vec::new();
{
for playerdata in pong.players.iter() {
match playerdata.player {
Player::Human(ref gp) => {
if gp.str == "mydev" {
vec.push(gp); //omitting this line of code fixes borrow checker issues
}
}
_ => {}
}
}
}
update_game(pong);
}
playground
This gives:
error[E0502]: cannot borrow `*pong` as mutable because `pong.players` is also borrowed as immutable
--> src/main.rs:52:17
|
41 | for playerdata in pong.players.iter() {
| ------------ immutable borrow occurs here
...
52 | update_game(pong);
| ^^^^ mutable borrow occurs here
53 | }
| - immutable borrow ends here
While I can understand the error to some extent, but coming from a C and Java background, I really struggle to get out of this problem. I am mainly confused why the immutable borrow is not released after the for loop ends. How would you write this in idiomatic Rust?
The error is a bit poorly worded, but I see your problem.
The error says the immutable borrow occurs in the for loop, which isn't quite correct. Instead, it occurs on the line you marked: vec.push(gp).
gp is an immutable reference to an object contained within pong.players. When you exit the loop, there is no immutable reference to pong.players itself, but there is a vector full of references to objects inside that vector.
pong.players : [ a, b, c, d, e]
^ ^ ^ ^ ^
vec : [&a, &b, &c, &d, &e]
Since you have outstanding immutable references to objects within pong.players, Rust has to consider pong.players as "implicitly" immutably borrowed, to ensure that none of its contents are mutated while there is still an immutable reference to that item. Since pong.players is a component of pong and is "implicitly" borrowed, pong itself has to be "implicitly" borrowed immutably as well.
In other words, the borrow of pong in game_loop lasts as such:
fn game_loop(pong: &mut Pong) {
let mut vec: Vec<&Gamepad> = Vec::new(); // <+ `vec`'s lifetime begins here
{ // |
for playerdata in pong.players.iter() { // <+ `pong.players.iter()` temporarily immutably borrows
// | `players` from `pong` for the iterator. `playerdata`
// | is a borrowed portion of `pong.players`.
// | As long as any `playerdata` exists, `pong.players`
// | is immutably borrowed by extension.
match playerdata.player { // <+ `playerdata.player` is a portion of `playerdata`.
Player::Human(ref gp) => { // <+ `gp` is a borrow of an element of `playerdata`.
if gp.str == "mydev" { // |
vec.push(gp); // <! At this point, `gp` is added to `vec`.
// | Since `gp` is inside `vec`, the reference to `gp`
// | is not dropped *until `vec` is dropped.
} // |
} // <- `gp`'s *lexical* lifetime ends here, but it may still
// | be inside `vec`. Any `gp` added to `vec` is still
// | considered borrowed.
_ => {} // |
} // <- `playerdata.player` is not longer lexically borrowed.
// | However, since `gp`, a portion of `playerdata.player`,
// | may still be borrowed, the compiler flags
// | `playerdata.player` as still borrowed.
} // <- `playerdata`'s borrow scope ends here, but since
// | `playerdata.player` may still be borrowed (due to the
// | fact that `vec` may contain references to elements of
// | playerdata.player), `playerdata` is still considered borrowed
} // <- the iterator over `pong.players` is dropped here. But since
// | `playerdata` might still be referenced in `vec`, `pong.players`
// | is still considered borrowed... and since `pong.players` is
// | implicitly borrowed, `pong` is implicitly borrowed.
update_game(pong); // <! When you reach this line, `pong` is implicitly borrowed because
// | there are references to something 'inside' it. Since you can't
// | have an immutable borrow and a mutable borrow at the same time
// | (to ensure you can't change something at the same time another
// | part of the program views it), `update_game(pong)` cannot accept
// | a mutable reference to `pong`.
} // <- At this point, `vec` is dropped, releasing all references to the
// | contents of `pong`. `pong` is also dropped here, because it is the
// | end of the function.
That explains the why. As for the how to solve it: Theoretically, the easiest solution would be to implement Clone on Gamepad (which can be easily done with #[derive(Clone)] if all of Gamepad's fields implement clone; the standard implementation is basically creating a new object by calling .clone on all of the fields of the original) and then use gp.clone() rather than just gp.
This has a (probably negligible) impact on the memory use of your program, but moreover, it can be infeasible if Gamepad uses external-library types that do not implement Clone - you can't implement Clone on those external types, because you don't define Clone or SomeExternalType in your project.
If impl Clone isn't available to you, you may need to refactor your code; reconsider why you need certain mutable or immutable borrows, and remove them if they're unnecessary. If that fails, you might need to look into other types of pointers like Cell, which I'm not qualified to give information about!
If you don't need to keep vec around and do stuff with it after update_game is called, consider this solution:
fn game_loop(pong: &mut Pong) {
{
let mut vec: Vec<&Gamepad> = Vec::new(); // <+ Vec is created
for playerdata in pong.players.iter() { // |
match playerdata.player { // |
Player::Human(ref gp) => { // |
if gp.str == "mydev" { // |
vec.push(gp); // |
} // |
} // |
_ => {} // |
} // |
} // |
for g_pad in vec { // |
// Do something with each gamepad // |
} // |
} // <- `vec` is dropped
// Since `vec` no longer exists, there are no more references
// to the contents of `pong`, and `update_game` can be called.
update_game(pong);
}
Hope this helps.
I'm learning Rust and I'm trying to cargo-cult this code into compiling:
use std::vec::Vec;
use std::collections::BTreeMap;
struct Occ {
docnum: u64,
weight: f32,
}
struct PostWriter<'a> {
bytes: Vec<u8>,
occurrences: BTreeMap<&'a [u8], Vec<Occ>>,
}
impl<'a> PostWriter<'a> {
fn new() -> PostWriter<'a> {
PostWriter {
bytes: Vec::new(),
occurrences: BTreeMap::new(),
}
}
fn add_occurrence(&'a mut self, term: &[u8], occ: Occ) {
let occurrences = &mut self.occurrences;
match occurrences.get_mut(term) {
Some(x) => x.push(occ),
None => {
// Add the term bytes to the big vector of all terms
let termstart = self.bytes.len();
self.bytes.extend(term);
// Create a new occurrences vector
let occs = vec![occ];
// Take the appended term as a slice to use as a key
// ERROR: cannot borrow `*occurrences` as mutable more than once at a time
occurrences.insert(&self.bytes[termstart..], occs);
}
}
}
}
fn main() {}
I get an error:
error[E0499]: cannot borrow `*occurrences` as mutable more than once at a time
--> src/main.rs:34:17
|
24 | match occurrences.get_mut(term) {
| ----------- first mutable borrow occurs here
...
34 | occurrences.insert(&self.bytes[termstart..], occs);
| ^^^^^^^^^^^ second mutable borrow occurs here
35 | }
36 | }
| - first borrow ends here
I don't understand... I'm just calling a method on a mutable reference, why would that line involve borrowing?
I'm just calling a method on a mutable reference, why would that line involve borrowing?
When you call a method on an object that's going to mutate the object, you can't have any other references to that object outstanding. If you did, your mutation could invalidate those references and leave your program in an inconsistent state. For example, say that you had gotten a value out of your hashmap and then added a new value. Adding the new value hits a magic limit and forces memory to be reallocated, your value now points off to nowhere! When you use that value... bang goes the program!
In this case, it looks like you want to do the relatively common "append or insert if missing" operation. You will want to use entry for that:
use std::collections::BTreeMap;
fn main() {
let mut map = BTreeMap::new();
{
let nicknames = map.entry("joe").or_insert(Vec::new());
nicknames.push("shmoe");
// Using scoping to indicate that we are done with borrowing `nicknames`
// If we didn't, then we couldn't borrow map as
// immutable because we could still change it via `nicknames`
}
println!("{:?}", map)
}
Because you're calling a method that borrows as mutable
I had a similar question yesterday about Hash, until I noticed something in the docs. The docs for BTreeMap show a method signature for insert starting with fn insert(&mut self..
So when you call .insert, you're implicitly asking that function to borrow the BTreeMap as mutable.
I'd like to have struct members that know their parent. This is approximately what I'm trying to do:
struct Parent<'me> {
children: Vec<Child<'me>>,
}
struct Child<'me> {
parent: &'me Parent<'me>,
i: i32,
}
fn main() {
let mut p = Parent { children: vec![] };
let c1 = Child { parent: &p, i: 1 };
p.children.push(c1);
}
I tried to appease the compiler with lifetimes without completely understanding what I was doing.
Here's the error message I'm stuck on:
error[E0502]: cannot borrow `p.children` as mutable because `p` is also borrowed as immutable
--> src/main.rs:13:5
|
12 | let c1 = Child { parent: &p, i: 1 };
| - immutable borrow occurs here
13 | p.children.push(c1);
| ^^^^^^^^^^ mutable borrow occurs here
14 | }
| - immutable borrow ends here
That makes some sense, but I'm not at all sure where to go from here.
It is not possible to create cyclic structures with borrowed pointers.
There is not any good way of achieving cyclic data structures at present; the only real solutions are:
Use reference counting with Rc<T> with a cyclic structure with Rc::new and Rc:downgrade. Read the rc module documentation and be careful to not create cyclic structures that use strong references, as these will cause memory leaks.
Use raw/unsafe pointers (*T).