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?
Related
This question already has an answer here:
Can I pass the same mutable trait object in multiple iterations of a loop without adding indirection?
(1 answer)
Closed 25 days ago.
Here's some simple code that seems like it should work:
use serde_json;
use std::io::Write;
fn test(writer: &mut dyn Write) {
serde_json::to_writer(writer, "test1").unwrap();
serde_json::to_writer(writer, "test2").unwrap();
}
But it produces the following error:
error[E0382]: use of moved value: `writer`
--> src/main.rs:35:27
|
33 | fn test(writer: &mut dyn Write) {
| ------ move occurs because `writer` has type `&mut dyn std::io::Write`, which does not implement the `Copy` trait
34 | serde_json::to_writer(writer, "test1").unwrap();
| ------ value moved here
35 | serde_json::to_writer(writer, "test2").unwrap();
| ^^^^^^ value used here after move
To get it to work, I have to jump through this hoop:
fn test(writer: &mut dyn Write) {
serde_json::to_writer(&mut *writer, "test1").unwrap();
serde_json::to_writer(writer, "test2").unwrap();
}
What is going on here? Why can I "manually" copy the ref by deref/re-referencing it, but it doesn't implement Copy?
This is specifically something to do with the generic type signature of serde_json::to_writer, because it also works fine with a different function:
fn test(x: &mut dyn Write) {
x.write_all(b"test1").unwrap();
x.write_all(b"test2").unwrap();
}
In Rust &T implements Copy. However, &mut T doesn't. It has to be moved (because of Aliasing NAND Mutability)
In your case writer being a &mut T is moved out into serde_json::to_writer and afterwards the reference is unusable for another call. However, for convenience Rust allows to borrow mutably from a mutable refenrence in simple cases - only if this borrow will die before the original mutable reference is used. This is what you did in your quesion, you may consider it as a "temporary reversable ownership transfer"
Trying to use it in other ways would fail. For example, this one uses the original mutable reference before the the secondary borrow is eliminated.
fn test(writer: &mut dyn Write) {
let mut w = &mut *writer;
serde_json::to_writer(writer, "test1").unwrap();
serde_json::to_writer(w, "test1").unwrap();
}
error[E0505]: cannot move out of `writer` because it is borrowed
--> src/main.rs:6:27
|
5 | let mut w = &mut *writer;
| ------------ borrow of `*writer` occurs here
6 | serde_json::to_writer(writer, "test1").unwrap();
| ^^^^^^ move out of `writer` occurs here
7 | serde_json::to_writer(w, "test1").unwrap();
| - borrow later used here
And this one tries to create multiple temprorary mutable borrows at the same time
fn test(writer: &mut dyn Write) {
let mut w = &mut *writer;
let mut w1 = &mut *writer;
serde_json::to_writer(w, "test1").unwrap();
}
error[E0499]: cannot borrow `*writer` as mutable more than once at a time
--> src/main.rs:6:18
|
5 | let mut w = &mut *writer;
| ------------ first mutable borrow occurs here
6 | let mut w1 = &mut *writer;
| ^^^^^^^^^^^^ second mutable borrow occurs here
7 | serde_json::to_writer(w, "test1").unwrap();
| - 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.
I can't quite understand why this compiles:
fn main() {
let mut v = vec![1,2,3];
for i in 1..v.len() {
v[i] = 20;
}
}
...and this doesn't:
fn main() {
let mut v = vec![1,2,3];
for (i,_) in v.iter().enumerate() {
v[i] = 20;
}
}
Error:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:6:13
|
4 | for (i,_) in v.iter().enumerate() {
| --------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
5 |
6 | v[i] = 20;
| ^ mutable borrow occurs here
In both cases we make an immutable borrow (one when call len(), other when we call iter()).
Thus, my expectation was that the 1st snippet should NOT compile -- we're making an mutable borrow when doing the assignment, when an immutable borrow exists.
What am I misunderstanding?
You are not actually making an immutable borrow in the first case, or rather, it ends after the call to len() returns (as len returns a primitive type not holding a reference to what it was used on). This means that your loop is perfectly fine, since you hold the one and only mutable object.
On the second one, you are creating a type that implements Iterator<Item = &u32> and then iterating on that iterator. The iterator has an immutable borrow to your collection (how else could you call next() on it otherwise?). This is a bit hidden, but that's where the immutable borrow is and why you cannot do what you did.
Typically, when working with iterators, and when you need to modify an element being iterated on, iter_mut is the way to go, for obvious reasons :-)
I'm trying to nail down ownership rules. I want to:
start with a mutable reference to a slice
make some edits to its contents
reduce the slice reference to a reference of a sub-slice and repeat
Below is my attempt:
pub fn example() {
// Make a mutable slice
let mut v = [0, 1, 2, 3];
// Make a mutable reference to said slice
let mut v_ref = &mut v[..];
while v_ref.len() > 1 {
// Involves some edits -> need mut
v_ref.swap(0, v_ref.len() - 1);
// Try to reduce slice to sub-slice (some simplification here)
// Errors!
let (v_l, v_h) = v.split_at_mut(v.len() / 2);
v_ref = v_l;
}
}
However I'm getting the errors:
error[E0502]: cannot borrow `*v_ref` as immutable because it is also borrowed as mutable
--> src/lib.rs:11:23
|
11 | v_ref.swap(0, v_ref.len() - 1);
| ----- ^^^^^ - mutable borrow ends here
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
error[E0499]: cannot borrow `v` as mutable more than once at a time
--> src/lib.rs:15:26
|
7 | let mut v_ref = &mut v[..];
| - first mutable borrow occurs here
...
15 | let (v_l, v_h) = v.split_at_mut(v.len() / 2);
| ^ second mutable borrow occurs here
...
18 | }
| - first borrow ends here
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/lib.rs:15:41
|
7 | let mut v_ref = &mut v[..];
| - mutable borrow occurs here
...
15 | let (v_l, v_h) = v.split_at_mut(v.len() / 2);
| ^ immutable borrow occurs here
...
18 | }
| - mutable borrow ends here
I understand that you can't have multiple references to an object in the same scope as a single mutable reference.
There should be a safe way to reduce a slice's range, as you're only reducing the scope of a current mutable reference. What's the best way to do that?
Problem 1: Using the same variable mutably and immutably
As Peter Hall points out, the code attempts to reference the variable v while there's a concurrent mutable reference to it, even though you don't care about v_ref anymore. A MCVE:
pub fn example() {
let mut v = 0;
let mut v_ref = &mut v;
println!("{}", v)
}
See also:
What are non-lexical lifetimes?
Problem 2: Using the same variable mutably and immutably
Then the code attempts to overlap mutable and mutable borrows in a single function call. A MCVE:
pub fn example() {
let mut v = [0, 1, 2, 3];
v.split_at_mut(v.len());
}
See also:
Cannot borrow as immutable because it is also borrowed as mutable in function arguments
Problem 3: Using the same variable mutably and mutably
Then the code has overlapping mutable borrows of v in the loop.
See also:
Cannot obtain a mutable reference when iterating a recursive structure: cannot borrow as mutable more than once at a time
All together:
pub fn example() {
let mut v = [0, 1, 2, 3];
let mut v_ref = &mut v[..];
while v_ref.len() > 1 {
let len = v_ref.len();
v_ref.swap(0, len - 1);
let (v_l, _) = { v_ref }.split_at_mut(len / 2);
v_ref = v_l;
}
}
I'm attempting to implement a dynamic programming problem in Rust to gain familiarity with the language. Like many dynamic programming problems, this uses memoization to reduce the running time. Unfortunately, my first-pass solution yields errors. I've pared the code down to the following. Warning - it's now a bit nonsensical:
use std::collections::HashMap;
fn repro<'m>(memo: &'m mut HashMap<i32, Vec<i32>>) -> Option<&'m Vec<i32>> {
{
let script_a = repro(memo);
let script_b = repro(memo);
}
memo.get(&0)
}
fn main() {}
The compilation error is:
error[E0499]: cannot borrow `*memo` as mutable more than once at a time
--> src/main.rs:6:30
|
5 | let script_a = repro(memo);
| ---- first mutable borrow occurs here
6 | let script_b = repro(memo);
| ^^^^ second mutable borrow occurs here
7 | }
| - first borrow ends here
Why is the variable memo borrowed multiple times? In my view, it should be borrowed once when I compute script_a, then that borrow ends, then it gets borrowed again for script_b.
Currently borrows last for the block they are defined in (#9113 might change this if implemented)
The problem is that script_a (that holds an immutable reference to a map) is valid for the whole block and you try to use a mutable reference to the same map:
let script_a = repro(memo);
let script_b = repro(memo);
// script_a is still alive
The bigger problem is the infinite loop. Anyway let script_a is a reference to data inside the hash map, so it's still borrowed by the time you call let script_b = repro(memo);.