Push to Vector in Hashmap - rust

Goal: Create a hashmap, add a vector to the hashmap, push to the vector
Code:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("first", Vec::new());
let get_option = map.get("first");
match get_option {
None => println!("invalid key"),
Some(v) => v.push("Chris"),
}
}
Error:
error[E0596]: cannot borrow `*v` as mutable, as it is behind a `&` reference
--> src/main.rs:12:20
|
12 | Some(v) => v.push("Chris"),
| - ^^^^^^^^^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable
| |
| help: consider changing this to be a mutable reference: `&mut Vec<&str>`

Your hashmap is mutable, but HashMap::get always returns an immutable reference. If you want a mutable reference to an element, use HashMap::get_mut.
let get_option = map.get_mut("first");
match get_option {
None => println!("invalid key"),
Some(v) => v.push("Chris"),
}
You'll see this a lot in Rust: a _mut version and a non-mutable version side-by-side. The idea of having mutability-polymorphic functions (a function whose mut status is a generic argument like a lifetime) has been floated before to the language developers, but it's usually been dismissed as too complicated and not worth the cost.

Related

Troubles understanding rust borrowing system

I'm going thru the rustlings exercises but I don't seem to understand how borrow semantics works.
I created this simple example (check the playground):
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec0", vec0);
println!("{} has content `{:?}`", "vec1", vec1);
}
which gives the following error:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `vec0` as immutable because it is also borrowed as mutable
--> src/main.rs:9:47
|
7 | let vec1 = &mut vec0;
| --------- mutable borrow occurs here
8 |
9 | println!("{} has content `{:?}`", "vec0", vec0);
| ^^^^ immutable borrow occurs here
10 |
11 | println!("{} has content `{:?}`", "vec1", vec1);
| ---- mutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
I though that when borrowing a value the original binding kept the ownership, that is, after the let vec1 = &mut vec0; vec0 should still own the vec.
Moreover, I don't understand why on line 9 on println!("{} has content `{:?}`", "vec0", vec0) an immutable borrow occurs. Isn't the vec still owned by vec0?
You're correct that vec0 is still the owner of the the underlying memory.
The reason println! needs to borrow vec0 is that the println! macro needs to be able to read from the vector in order to print it, therefore it needs a read-only reference. A read-only reference is automatically created and goes out of scope inside this macro.
The reason that you are getting a compiler error here is that you are violating the borrow checker rules:
At any given time, you can have either one mutable reference or any number of immutable references.
The best way to understand how println references it's arguments is by using cargo-expand which will show the result of macro expansion. For your code it expands to
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &mut vec0;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", " has content `", "`\n"],
&match (&"vec0", &vec0) { // Immutable borrow
_args => [
::core::fmt::ArgumentV1::new(_args.0, ::core::fmt::Display::fmt),
::core::fmt::ArgumentV1::new(_args.1, ::core::fmt::Debug::fmt),
],
},
));
};
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", " has content `", "`\n"],
&match (&"vec1", &vec1) { // Immutable borrow
_args => [
::core::fmt::ArgumentV1::new(_args.0, ::core::fmt::Display::fmt),
::core::fmt::ArgumentV1::new(_args.1, ::core::fmt::Debug::fmt),
],
},
));
};
}
As you can see println takes immutable reference to its arguments.(Which means vec0 stills owns the vector). But the problem here is that Rust enforces "multiple readers or single writer" rule at compile time. As long as there is mutable reference to a value you cannot use the owner until the mutable reference goes away. Similarly as long as there is multiple shared references to value not even it's owner can modify it.
For example, this will compile,
fn main() {
let mut vec0: Vec<i64> = Vec::new();
{
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec1", vec1);
} // The mutable reference goes out of scope here.
println!("{} has content `{:?}`", "vec0", vec0);
}
You can't have two mutable references to the same value at the same time. If you reorder the lines in your function like this:
fn main() {
let mut vec0: Vec<i64> = Vec::new();
println!("{} has content `{:?}`", "vec0", vec0);
let vec1 = &mut vec0;
println!("{} has content `{:?}`", "vec1", vec1);
}
, there will be no problem, because in that variant vec0 is not accessed after the moment a mutable reference to it was created.
If vec1 was a normal (immutable) reference, there would be no problem even with your original line order, because having multiple immutable (read-only) references is not a problem:
fn main() {
let mut vec0: Vec<i64> = Vec::new();
let vec1 = &vec0;
println!("{} has content `{:?}`", "vec0", vec0);
println!("{} has content `{:?}`", "vec1", vec1);
}
References are most often used for function parameters, when you don't want to move a value, but only pass a reference to it. Only when you need to change the underlying value inside the function, you need to make the reference mutable.

Can I mutate a vector with a borrowed element?

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.

Linked list in Rust with nodes owned by HashMap

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();
// ...
}

Why can I not borrow a variable as mutable more than once at a time with a &mut Box<T> while &mut T works?

I'm trying to implement a linked list in Rust and I'm having some trouble understanding the difference between these two functions:
enum List<T> {
Nil,
Cons(T, Box<List<T>>)
}
fn foo<T>(list: &mut Box<List<T>>) {
match **list {
List::Nil => return,
List::Cons(ref mut head, ref mut tail) => {
// ...
}
}
}
fn bar<T>(list: &mut List<T>) {
match *list {
List::Nil => return,
List::Cons(ref mut head, ref mut tail) => {
// ...
}
}
}
foo fails to compile, with the following error:
error[E0499]: cannot borrow `list` (via `list.1`) as mutable more than once at a time
--> src/main.rs:66:34
|
66 | List::Cons(ref mut head, ref mut rest) => {
| ------------ ^^^^^^^^^^^^ second mutable borrow occurs here (via `list.1`)
| |
| first mutable borrow occurs here (via `list.0`)
...
69 | }
| - first borrow ends here
However, bar compiles and runs perfectly. Why does bar work, but not foo? I am using Rust version 1.25.
This can be simplified to
fn foo(v: &mut Box<(i32, i32)>) {
match **v {
(ref mut head, ref mut tail) => {}
}
}
or
fn foo(v: &mut Box<(i32, i32)>) {
let (ref mut head, ref mut tail) = **v;
}
The problem is that Box is a a strange, in-between type.
Way back in Rust's history, Box was special-cased by the compiler; it knew a lot of the details of Box, but this meant that it was "magic" and no one else could implement something that worked like Box.
RFC 130 proposed changing that; making Box "just another type". Unfortunately, this still hasn't been fully transitioned.
The details are nuanced, but basically the current borrow checker handles pattern-matching syntactically, not semantically. It needs to do this to prevent some unsoundness issues.
In the future, non-lexical lifetimes (NLL) just magically fix this; you don't have to to anything (hooray!).
Until then, you can explicitly get back to a &mut T with this ugly blob:
match *&mut **list {
Or call DerefMut explicitly:
match *std::ops::DerefMut::deref_mut(list) {
However, there's very little reason to accept a &mut Box<T>.
See also:
Destructuring boxes into multiple mutable references seems broken #30104
Bad / misleading error message with auto deref and mutable borrows of multiple fields #32930
Why can I not borrow a boxed vector content as mutable?
Confused by move semantics of struct fields inside a Box
Moving out of boxed tuple

Why does an immutable borrow in a loop last outside of its lexical scope?

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.

Resources