Mutate an object which was taken from a vector - rust

I have trouble solving an obvious simple problem.
Basically I want to push an instance of a structure to a vector to get it out later and to modify the object by calling a function implemented for the structure.
To simplify the case, I created the following test code, which reflects in my opinion to the same problem.
let mut strings = Vec::new();
strings.push("Hello".to_string());
let string_option = strings.last();
let string = string_option.unwrap();
string.shrink_to(1);
This has the compile error
error[E0596]: cannot borrow `*string` as mutable, as it is behind a `&` reference
--> src/main.rs:89:5
|
88 | let string = string_option.unwrap();
| ------ help: consider changing this to be a mutable reference: `&mut String`
89 | string.shrink_to(1);
| ^^^^^^^^^^^^^^^^^^^ `string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
Then I tried sheer endless variants like
let mut strings = Vec::new();
strings.push("Hello".to_string());
let string_option = strings.last().as_mut();
let string = string_option.unwrap();
string.shrink_to(1);
... or ...
let mut strings = Vec::new();
strings.push("Hello".to_string());
let string_option = strings.last().as_deref_mut();
let string = string_option.unwrap();
string.shrink_to(1);
Actually the code shown above is a simplification from this code, which I originally wanted to do.
struct Bar {
data: Vec<String>
}
impl Bar {
fn shrink_first(&mut self) {
let s_opt = self.data.last().as_mut(); // s_opt is of type Option<&mut &String>
let s = s_opt.unwrap(); // s is of type &mut & String
s.shrink_to(1);
}
}
The code above brings the following errors ...
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:67:21
|
67 | let s_opt = self.data.last().as_mut(); // s_opt is of type Option<&mut &String>
| ^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
68 |
69 | let s = s_opt.unwrap(); // s is of type &mut & String
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error[E0596]: cannot borrow `**s` as mutable, as it is behind a `&` reference
--> src/main.rs:70:9
|
70 | s.shrink_to(1);
| ^^^^^^^^^^^^^^ cannot borrow as mutable
But in my opinion it always has the same root causes, but I have not figured out what to do.

Simply change strings.last() to strings.last_mut().
The last() method returns a standard (immutable) reference (to be more precise, Option<&T>).
To be able to mutate the last String in the vector, you need to get a mutable reference via last_mut().

Related

rustlings move_semantics2 why passing reference doest not work?

i am trying Rust by doing the restlings exercices that is a very good approach to start with but there is something that i do not understand.
Exercice: move_semantics2
I understand that in order to initialize vec1 with the content of vec0 without taking the ownership away we have to either clone vec0 or to pass by reference. The issue is that this code, that passes references doesn't seem to work.
I wanna understand why, any idea ?
// move_semantics2.rs
// Make me compile without changing line 13 or moving line 10!
// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand for a hint.
// I AM NOT DONE
fn main() {
let vec0 = Vec::new();
let mut vec1 = fill_vec(&vec0);
// Do not change the following line!
println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: &Vec<i32>) -> &Vec<i32> {
let mut vec = vec;
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
this is the error i am getting :
⚠️ Compiling of exercises/move_semantics/move_semantics2.rs failed! Please try again. Here's the output:
warning: variable does not need to be mutable
--> exercises/move_semantics/move_semantics2.rs:8:9
|
8 | let mut vec1 = fill_vec(&vec0);
| ----^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
error[E0596]: cannot borrow `*vec1` as mutable, as it is behind a `&` reference
--> exercises/move_semantics/move_semantics2.rs:13:5
|
8 | let mut vec1 = fill_vec(&vec0);
| -------- consider changing this binding's type to be: `&mut Vec<i32>`
...
13 | vec1.push(88);
| ^^^^^^^^^^^^^ `vec1` is a `&` reference, so the data it refers to cannot be borrowed as mutable
warning: variable does not need to be mutable
--> exercises/move_semantics/move_semantics2.rs:19:9
|
19 | let mut vec = vec;
| ----^^^
| |
| help: remove this `mut`
error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference
--> exercises/move_semantics/move_semantics2.rs:21:5
|
19 | let mut vec = vec;
| ------- consider changing this binding's type to be: `&mut Vec<i32>`
20 |
21 | vec.push(22);
| ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference
--> exercises/move_semantics/move_semantics2.rs:22:5
|
19 | let mut vec = vec;
| ------- consider changing this binding's type to be: `&mut Vec<i32>`
...
22 | vec.push(44);
| ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0596]: cannot borrow `*vec` as mutable, as it is behind a `&` reference
--> exercises/move_semantics/move_semantics2.rs:23:5
|
19 | let mut vec = vec;
| ------- consider changing this binding's type to be: `&mut Vec<i32>`
...
23 | vec.push(66);
| ^^^^^^^^^^^^ `vec` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error: aborting due to 4 previous errors; 2 warnings emitted
For more information about this error, try `rustc --explain E0596`.
I think your misconception stems from this line in fill_vec():
let mut vec = vec;
That line is not making a copy of the original vector, instead it tries to make the original immutable reference to the passed in vector mutable, which naturally the compiler does not allow. If your intent was to make a copy of the the passed-in vector, you would want your function to look like this:
fn fill_vec(vec: &Vec<i32>) -> Vec<i32> {
let mut new_vec = vec.clone();
new_vec.push(22);
new_vec.push(44);
new_vec.push(66);
new_vec
}
Note that this new version uses clone() to copy the original vector, and instead of returning a reference to a vector, it returns a new vector.

Get first and all of an iterator. In Rust

What I am trying to do
I have in iterator returned from std::str::SplitWhitespace, I need the first element, and a vector of all elements.
What I have tried
I tried to use peek. However this seems to need a mutable (I can't we why), and I end up with borrowing errors.
Simplified code, with compile errors.
fn main(){
let line = "hello, world";
let mut tokens = line.split_whitespace().peekable();
if let Some(first) = tokens.peek() {
//println!("{first}"); //works
//println!("{tokens:?}"); // works
println!("{first}\n{tokens:?}"); //compile error
}
}
error[E0502]: cannot borrow `tokens` as immutable because it is also borrowed as mutable
--> src/main.rs:7:29
|
4 | if let Some(first) = tokens.peek() {
| ------------- mutable borrow occurs here
...
7 | println!("{first}\n{tokens:?}"); //error
| --------------------^^^^^^-----
| | |
| | immutable borrow occurs here
| mutable borrow later used here
If I un-comment the two printlns, and comment the erroneous one. then It works. This lead me to adding a clone let first = first.clone();, before the printlns. This fixed it, but I am wondering if there is a better way.
The simplest way to achieve this is to just collect the vector, then get the first element:
let tokens: Vec<_> = line.split_whitespace().collect();
if let Some(first) = tokens.first() {
println!("{first}\n{tokens:?}");
}
Note the type of tokens will be Vec<&str> -- a vector of string slices that are borrowed from line. If you instead want a vector of owned strings (Vec<String>), then you need to map each element to an owned string:
let tokens: Vec<_> = line.split_whitespace().map(|s| s.to_owned()).collect();

When should I make a closure mut?

Let's say I have this code:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
c();
It doesn't compile and generates this error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src\test.rs:120:9
|
119 | let c = || s.push_str(" yo");
| - - calling `c` requires mutable binding due to mutable borrow of `s`
| |
| help: consider changing this to be mutable: `mut c`
120 | c();
| ^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `test` due to previous error
Why c(); cannot borrow as mutable? It cannot borrow what as mutable? c? In order to make it work, I have to change it to:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
c();
But here I'm just defining a closure c. I'll not modify it, like c = || x;. Why must define it as let mut c?
But here I'm just defining a closure c. I'll not modify it, like c = || x;. Why must define it as let mut c?
Because a closure is fundamentally a structure, each captured item being a member of that structure.
So your code is roughly equivalent to this:
struct S<'a>(&'a mut String);
impl S<'_> {
fn call(&mut self) {
self.0.push_str("yo");
}
}
fn main() {
let mut s = "hi".to_string();
let c = S(&mut s);
c.call();
}
And that fails to compile with more or less the same error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src/main.rs:14:5
|
13 | let c = S(&mut s);
| - help: consider changing this to be mutable: `mut c`
14 | c.call();
| ^^^^^^^^ cannot borrow as mutable
Now you might object that that's because I defined fn call(&mut self), but if you don't you get the internal part of the same error:
error[E0596]: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
--> src/main.rs:8:9
|
7 | fn call(&self) {
| ----- help: consider changing this to be a mutable reference: `&mut self`
8 | self.0.push_str("yo");
| ^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
That is you can't modify an &mut through an &. Because if you did you could create multiple &s to the same &mut through which you could modify the pointee, and that would essentially give you multiple &mut.
Which is not allowed by Rust's semantics:
At any given time, you can have either one mutable reference or any number of immutable references.
It may not look like c needs to be mutable because you aren't modifying c itself, but for closure types, the mut keyword is what allows it to mutate any external state. It changes the type of the closure to be a FnMut, which the docs refer to as "a mutably capturing closure".
It's about ownership. mut here does not mean that you will mutate c, but that you require mut-level access to the closure in order to execute it.
c borrows s mutably. This should be fairly obvious, because calling c() modifies s.
Now imagine if c would be usable without mut:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
let c1 = &c;
let c2 = &c;
c1();
c2();
Here, both c1 and c2 would have mutable access to s simultaneously, which is not possible according to Rusts borrowing rules. This is prevented automatically by the compiler, as it changes the type of the closure to FnMut as soon as you access a variable mutably from within the closure.
Then, you need mut access to the closure to execute it and the case becomes a compiler error:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
let c1 = &mut c;
let c2 = &mut c;
c1();
c2();
error[E0499]: cannot borrow `c` as mutable more than once at a time
--> src/main.rs:5:10
|
4 | let c1 = &mut c;
| ------ first mutable borrow occurs here
5 | let c2 = &mut c;
| ^^^^^^ second mutable borrow occurs here
6 |
7 | c1();
| -- first borrow later used here

Access variable after it was borrowed

I am assigning data to properties of a struct, but the following error appears:
error[E0382]: borrow of partially moved value: `super_hero`
--> src/main.rs:16:22
|
13 | for mut chunk in super_hero.description_chunks.unwrap() {
| -------- `super_hero.description_chunks` partially moved due to this method call
...
16 | println!("{:?}", &super_hero);
| ^^^^^^^ value borrowed here after partial move
|
note: this function takes ownership of the receiver `self`, which moves `super_hero.description_chunks`
--> /Users/someuser/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:752:25
|
752 | pub const fn unwrap(self) -> T {
| ^^^^
= note: partial move occurs because `super_hero.description_chunks` has type `std::option::Option<Vec<Chunk>>`, which does not implement the `Copy` trait
help: consider calling `.as_ref()` to borrow the type's contents
|
13 | for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
The following is the code where I am assigning data to properties of a struct:
let super_hero_description = "several years ago.";
let mut super_hero = SuperHero::new(super_hero_description);
super_hero.description_chunks = Option::from(super_hero.get_decription_chunks(DescriptionTypes::NotVillan));
for mut chunk in super_hero.description_chunks.unwrap() {
chunk.data = Option::from(chunk.get_data(DescriptionTypes::NotVillan).await);
}
println!("{:?}", &super_hero);
The error does not happen until I try to print the super_hero at the end.
Oh, and if I follow the recommendation rust gives me
for mut chunk in super_hero.description_chunks.as_ref().unwrap() {
| +++++++++
I end up with another error:
error[E0594]: cannot assign to `chunk.data`, which is behind a `&` reference
--> src/main.rs:14:9
|
13 | for mut subdivision in super_hero.description_chunks.as_ref().unwrap() {
| ------------------------------------- this iterator yields `&` references
14 | chunk.data = Option::from(chunk.get_data()(DescriptionTypes::NotVillan).await);
| ^^^^^^^^^^^^ `chunk` is a `&` reference, so the data it refers to cannot be written
rustc is correct, it just needs a little adjustment: instead of as_ref() use as_mut(), that converts &mut Option<T> to Option<&mut T> instead of &Option<T> to Option<&T>.
The problem is that unwrap() requires an owned Option: see Reference to unwrapped property fails: use of partially moved value: `self`.

Borrow checker complains for closure inside loop if type not provided explicitly

I have this code, for which borrow checker shows error:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=55d050b6f25410ce0e17ef9e844b048d
fn f1(v: &str) {
}
fn main() {
let c = |v| f1(v);
for _ in 0..1 {
let s = String::new();
c(&s);
}
}
|
10 | c(&s);
| - ^^ borrowed value does not live long enough
| |
| borrow later used here
11 | }
| - `s` dropped here while still borrowed
But if I add explicit type to closure, code compiles let c = |v: &str| f1(v);
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=54ca20dff5bdf1831ec705481e4936bb
Can someone explain why it works in second case and not in first, as I understand rust correctly infers same type in first example (as it works if I run closure outside of loop)?

Resources