This is my code.
I am trying to create a Hashmap with i32 as keys and HashSets as values. But when I compile I get a warning that the variable(HashSet) does not need to be mutable. But I am clearly inserting values to the HashSet.
use std::collections::*;
fn main() {
let mut map = HashMap::new();
for i in 0..3 {
// the warning will disappear if I remove the 'mut' keyword
let mut set = HashSet::new();
map.insert(i, set);
}
for (i, set) in &mut map {
for j in *i..(i+5) {
//here I am inserting values to the hashset , therefore set has to be mutable
set.insert(j);
}
}
for (i, set) in &map {
println!("{i} : {:?}", set);
}
}
The warning that I get.
Compiling playground v0.0.1 (/playground)
warning: variable does not need to be mutable
--> src/main.rs:6:13
|
6 | let mut set = HashSet::new();
| ----^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
warning: `playground` (bin "playground") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 2.84s
Running `target/debug/playground`
The code compiles fine if I remove the mut keyword. You can try running it on Rust Playground as I did.
I tried to insert elements to an immutable set and I was not able to.
use std::collections::*;
fn main() {
let set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(3);
println!("{:?}", set);
}
Compilation Error
Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow `set` as mutable, as it is not declared as mutable
--> src/main.rs:5:5
|
4 | let set = HashSet::new();
| --- help: consider changing this to be mutable: `mut set`
5 | set.insert(1);
| ^^^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `set` as mutable, as it is not declared as mutable
--> src/main.rs:6:5
|
4 | let set = HashSet::new();
| --- help: consider changing this to be mutable: `mut set`
5 | set.insert(1);
6 | set.insert(2);
| ^^^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `set` as mutable, as it is not declared as mutable
--> src/main.rs:7:5
|
4 | let set = HashSet::new();
| --- help: consider changing this to be mutable: `mut set`
...
7 | set.insert(3);
| ^^^^^^^^^^^^^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `playground` due to 3 previous errors
So why is the compiler saying that the variable set does not need to be declared mutable?
Immutability in Rust is not the same as constantness of C++ if you are owning the object. Owned things are always mutable, because, why not? You are the owner. You can mutate. Mutability comes close to C++ const when we are talking about borrowing.
So when you are creating a set with let set = HashSet::new();, then the variable name set is immutable. But the object created is mutable. And the insert function takes the ownership of the set, and so it can mutate.
A more concise example to see this may be:
let set: HashSet<i32> = HashSet::new();
let mut set2 = set;
You can always move an immutable object that you own into a mutable, which effectively only renames it and makes mutable (no copy or clone here).
While, for references, the constant correctness is held:
let mut set: HashSet<i32> = HashSet::new();
let set_ref: &HashSet<i32> = &set;
let set_mutref: &mut HashSet<i32> = set_ref; // compile error
// ^^^^^^^ types differ in mutability
TLDR: when you call map.insert(set) you pass ownership (and therefore mutability) from set to map.
Longer answer:
The mut in let mut set = HashSet::new(); gives the following extra capabilities:
reassignment - you can write set = other_hash_set; to reassign the value
mutable referencing - you can write &mut set to get a mutable reference to the set
When you call set.insert(something) (when set has type HashSet, that is transformed by the compiler to HashSet::insert(&mut set, something), which clearly uses option 2 from above, so the mut keyword would be needed.
But your code never does that. in your loop, you write for (i, set) in &mut map. In this case, because &mut HashMap<K, V> implements IntoIterator, this works, and the type of each element is (&K, &mut V). So set here has type &mut HashSet<i32>, so the mut keyword on the binding isn't needed.
I like to think of mut here as "part of the name of the variable". This explains why you can do the following:
let mut i = 5;
let j = i;
let mut k = j;
It's also worth remembering that mutability in Rust often doesn't have the same traps that it does in other langauges.
If you're working with references, the mutability is enforced how you'd expect. But if you're working with owned data, it's not possible for there to be some leftover references that have the data change underneath them. Once you're operating on owned data, you know noone else has a reference.
Related
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
As per my understanding, there can be multiple immutable references at a time but if there is a mutable reference it can be the only usable reference.
Why does the following code work?:
fn main() {
let mut y = String::from("bar");
let f: &mut String = &mut y;
let f2: &String = &(*f);
// not allowed since mutable reference already exists
// let f3: &String = &y;
println!("{}, ", f.as_str());
println!("{}", f2.as_str());
}
Edit: Another part of my question which I guess isn't obvious is: why am I not allowed to create f3 (like I am doing in the commented line) when it is exactly the same thing as f2 and created similarly by refrencing y.
Because the compiler is smart enough to know if the data actually is used as mutable before it is used as immutable. If you change the code at all to use the mutable reference first, it fails.
fn main() {
let mut y = String::from("bar");
let f: &mut String = &mut y;
let f2: &String = &(*f);
f.clear();
// not allowed since mutable reference already exists
// let f3: &String = &y;
println!("{}, ", f.as_str());
println!("{}", f2.as_str());
}
Here's a link to a live example. The error, as you'd expect, mentions you cannot have an immutable reference if a mutable one exists.
error[E0502]: cannot borrow `*f` as mutable because it is also borrowed as immutable
--> src/main.rs:6:5
|
5 | let f2: &String = &(*f);
| ----- immutable borrow occurs here
6 | f.clear();
| ^^^^^^^^^ mutable borrow occurs here
...
12 | println!("{}", f2.as_str());
| ----------- immutable borrow later used here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error
In short, you can only have one borrow if you have a mutable reference, but the compiler is intelligent enough to know when the value cannot change: in your example, f cannot change when it is used before f2 is used, so it knows it doesn't change.
Why does the following fail to compile (2018 edition)
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
{
let _r2 = &s;
}
println!("{}", r1);
}
Why the compiler fails to notice that _r2 is unused and successfully compile the above?
It complains that we have both mutable and immutable refs and mutable is used in println.
the confusing part is that literature (books etc...) talk about "using block to restrict borrowing scope. "Beginning Rust" p348 for example. So I found it confusing that we advocate for such practices but it (sometimes) does not work.
But it does work here; the scope of _r2 is restricted by the block it's
declared in. The problem is just that r1 is visible in this scope as well.
That is, the error message is not saying "you can't println because there are both mutable and immutable borrows at that point", but "you can't declare _r2 because there is already a mutable borrow at that point". println only appears as a reason why r1 is still alive at the point of _r2's declaration.
You can see it from the error message:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> src/main.rs:5:19
|
3 | let r1 = &mut s;
| ------ mutable borrow occurs here
4 | {
5 | let _r2 = &s;
| ^^ immutable borrow occurs here
6 | }
7 | println!("{}", r1);
| -- mutable borrow later used here
^^ points at the actual error location; -- are other related locations.
You can only do like this,
fn main(){
let mut s = String::from("hello");
let r1 = &mut s;
{
let r2 = &r1;
}
println!("{}", r1);
}
I've read these docs: https://doc.rust-lang.org/rust-by-example/scope/borrow/mut.html
I've also read this question: (Cannot borrow immutable borrowed content as mutable)
The docs helped me understand how to declare borrowing as mutable (I think):
let mut (part1, part2) = someTuple;
But I'm haven't been able to find explicit instructions on what borrowing as an immutable looks like. This is my guess:
let (part1, part2) = someTuple;
I know this is a super basic question, but Googling it took me way off into the deep end of explanations and I'm still trying to get my bearings in the most simple of contexts.
How do I borrow as mutable vs an immutable in Rust?
let x = 0;
let immutable_borrow = &x; //borrow as immutable
//to borrow as mutable the variable needs to be declared as mutable
let mut y = 1;
let mutable_borrow = &mut y; //borrow as mutable
Note 1: you can borrow a variable either as immutable or mutable in the same scope, meaning you can't do this:
let mut x = 0;
let immutable_borrow = &x;
let mutable_borrow = &mut x;
Why?
Because if you would have mutable and immutable references of the same variable, then the data of that variable could change through that mutable reference and that could cause a lot of problems.
Note 2: you can immutably borrow a variable endless times but you can mutably borrow a variable only once.
//You can do this
let x = 0;
let x1 = &x;
let x2 = &x;
//...
//But you can't do this
let mut y = 0;
let y1 = &mut y;
let y2 = &mut y; //won't compile if you use y1 after you declare y2
Why?
As mentioned above. One mutable reference could change the data all the other mutable references are poiting to without them knowing. That could cause a lot of problems. But having multiple immutable references is okay, because the data can't be unexpectedly changed.
Ejdrien answers demonstrates the difference between mutable and immutable borrows, however it does not address a subtitle in your question, which is that you are performing borrows as part of pattern matching.
When you write
let (mut part1, mut part2) = someTuple;
you are binding the contents of someTuple to the mutable variables part1 and part2 by moving them. Unless the contents of someTuple were Copyable, the variables part1 and part2 become the exclusive owners of their respective values. If you attempt to access someTuple later by writing, e.g.
println!("{}", someTuple.0);
you'll receive a compile error from the borrow checker that resembles
error[E0382]: borrow of moved value: `someTuple.0`
--> main.rs:6:20
|
4 | let (mut part1, mut part2) = someTuple;
| --------- value moved here
5 |
6 | println!("{}", someTuple.0);
| ^^^^^^^^^^^ value borrowed here after move
In this particular context, there are two ways to inform the compiler that we want to only borrow the contents of someTuple. The first is the technique that Ejdrien described, which is explicitly borrowing the tuple and the performing the pattern matching against then resulting reference:
// Produce two mutable references
let (part1, part2) = &mut someTuple;
// Produce two immutable references
let (part1, part2) = &someTuple;
The problem with this approach is that we are forced to borrow everything in the same way. What if we only want a mutable reference to someTuple.0, and want to retrieve someTuple.1 as a copy, or as an immutable reference? For the tuple example here, this may not seem too critical, but for more complex cases of pattern matching, having this type of control is much more important.
This brings us two the second solution: binding references. Instead of the above, we can write
// Produce two mutable references
let (ref mut part1, ref mut part2) = someTuple;
// Produce two immutable references
let (ref part1, ref part2) = someTuple;
Here, we explicitly state how we want to bind each variable in the pattern matching. The key here is that we are free to intermix mutable and immutable borrows, so the following is also entirely valid:
// Produce immutable reference and one mutable reference
let (ref part1, ref mut part2) = someTuple;
println!("{}", &someTuple.0); // Make a second immutable reference someTuple.0
*part2 = ... // Mutate someTuple.1
println!("{}", part1); // Continue using the immutable reference
If we swap the above with an explicit mutable borrow on the right hand side, we'll once again receive errors from the borrow checker due to simultaneous mutable and immutable references:
let (part1, part2) = &mut someTuple;
println!("{}", &someTuple.0);
*part2 = ... // Mutate someTuple.1
println!("{}", part1);
produces
error[E0502]: cannot borrow `someTuple.0` as immutable because it is also borrowed as mutable
--> main.rs:6:20
|
4 | let (part1,part2) =&mut someTuple;
| -------------- mutable borrow occurs here
5 |
6 | println!("{}", &someTuple.0);
| ^^^^^^^^^^^^ immutable borrow occurs here
...
9 | println!("{}", part1);
| ----- mutable borrow later used here
error: aborting due to previous error
In the context of a crypto problem, to decrease verbosity, I'm "naming" a slice of v as block, doing some stuff to it, but then trying to verify the result of do_stuff on the whole of v:
fn x() {
let mut v = vec![0; 32];
let block = &mut v[0..16];
do_stuff(block);
check_stuff(&v);
do_stuff(block);
}
fn do_stuff(_: &mut [i32]) {}
fn check_stuff(_: &[i32]) {}
The borrow checker complains:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/lib.rs:6:17
|
3 | let block = &mut v[0..16];
| - mutable borrow occurs here
...
6 | check_stuff(&v);
| ^^ immutable borrow occurs here
7 | do_stuff(block);
| ----- mutable borrow later used here
I'm aware of the kind of guarantee this is trying to provide. However, assuming I know what I'm doing, is there an idiomatic way to give a name to the slice without having to use do_stuff(&mut v[0..16]) or having to make copies every time?