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;
}
}
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
The following code produces interesting results:
use std::thread;
fn main() {
let mut handles = Vec::new();
let mut v = vec![1, 2, 3, 4];
for x in v.chunks_exact_mut(2) {
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", x);
});
handles.push(handle);
}
for h in handles { h.join().unwrap(); }
}
error[E0597]: `v` does not live long enough
--> src/main.rs:7:14
|
7 | for x in v.chunks_exact_mut(2) {
| ^^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `v` is borrowed for `'static`
...
16 | }
| - `v` dropped here while still borrowed
Why does 'chunking' v change the lifetime? Without 'chunking' v, the code performs correctly. So why now does it throw an error?
The problem here is that thread::spawn completely decouples the lifetime from the rest, as the thread might continue to run while main is already finished.
x is a reference to a variable in main, and there is no guarantee that main lives longer than the thread.
I think what you really want here is a threading helper library like rayon, as they already solve those problems internally:
use rayon::prelude::*;
fn main() {
let mut v = vec![1, 2, 3, 4];
v.par_chunks_exact_mut(2).for_each(|x: &mut [i32]| {
let thread_id = std::thread::current().id();
println!("{:?}: Here's a vector: {:?}", thread_id, x);
});
}
ThreadId(5): Here's a vector: [1, 2]
ThreadId(2): Here's a vector: [3, 4]
Without "chunking" v, you're iterating over Vec<i32>. This iterator produces items of type i32, so, no references, no lifetimes, the requirements for thread::spawn() (specifically the 'static requirement) are met.
chunks_exact_mut(), however, is defined on slices and gives iterator over &mut [T], so it does have a reference. And since this reference refers v, which exists in main(), it is not 'static and does not work.
You can observe the same problem if you'll iterate over &v instead of v, since that iterator gives you &i32s (playground):
error[E0597]: `v` does not live long enough
--> src/main.rs:7:14
|
7 | for x in &v {
| ^^
| |
| borrowed value does not live long enough
| argument requires that `v` is borrowed for `'static`
...
16 | }
| - `v` dropped here while still borrowed
Other than that, I'd recommend using rayon as #Finomnis suggested.
I'm implementing code that handles a vector of length k * n and creates
k points of length n that reference a slice of the original vector:
struct Point<'a> {
values: &'a [f32],
}
impl<'a> Point<'a> {
pub fn new(values: &'a [f32]) -> Self {
Point { values }
}
pub fn dist_euclidian(&self, point: &Point) -> Result<f32, &str> {
unimplemented!()
}
}
When I try to test it:
#[test]
fn test_euclidian_distance() {
let mut v1 = vec![7.0, 11.0];
let mut v2 = vec![40.0, -27.0];
let p1: Point = Point::new(&v1[..]);
let p2: Point = Point::new(&v2[..]);
assert!((p1.dist_euclidian(&p2).unwrap() - 50.32).abs() <= 0.01);
v1[0] = 0.0;
v1[1] = -4.0;
v2[0] = 8.0;
v2[1] = 100.0;
assert!((p1.dist_euclidian(&p2).unwrap() - 104.3072).abs() <= 0.01);
}
I get the following error(s):
error[E0502]: cannot borrow `v1` as mutable because it is also borrowed as immutable
--> src/k_means/point.rs:56:9
|
51 | let p1: Point = Point::new(&v1[..]);
| -- immutable borrow occurs here
...
56 | v1[0] = 0.0;
| ^^ mutable borrow occurs here
...
61 | assert!((p1.dist_euclidian(&p2).unwrap() - 104.3072).abs() <= 0.01);
| -- immutable borrow later used here
error[E0502]: cannot borrow `v1` as mutable because it is also borrowed as immutable
--> src/k_means/point.rs:57:9
|
51 | let p1: Point = Point::new(&v1[..]);
| -- immutable borrow occurs here
...
57 | v1[1] = -4.0;
| ^^ mutable borrow occurs here
...
61 | assert!((p1.dist_euclidian(&p2).unwrap() - 104.3072).abs() <= 0.01);
| -- immutable borrow later used here
error[E0502]: cannot borrow `v2` as mutable because it is also borrowed as immutable
--> src/k_means/point.rs:58:9
|
52 | let p2: Point = Point::new(&v2[..]);
| -- immutable borrow occurs here
...
58 | v2[0] = 8.0;
| ^^ mutable borrow occurs here
...
61 | assert!((p1.dist_euclidian(&p2).unwrap() - 104.3072).abs() <= 0.01);
| --- immutable borrow later used here
error[E0502]: cannot borrow `v2` as mutable because it is also borrowed as immutable
--> src/k_means/point.rs:59:9
|
52 | let p2: Point = Point::new(&v2[..]);
| -- immutable borrow occurs here
...
59 | v2[1] = 100.0;
| ^^ mutable borrow occurs here
60 |
61 | assert!((p1.dist_euclidian(&p2).unwrap() - 104.3072).abs() <= 0.01);
| --- immutable borrow later used here
Is there a safe way of doing what I intend to do?
It's unfortunate that Rust's references have a name similar to storing "by reference" in other languages, but that's not what they are. Rust's references are for temporary views into data, when you want to limit usage of that data to a certain scope and preventing it from being used outside that scope. That is the opposite of what you need here.
If you want to keep something, don't use temporary references for it. Use owned values instead, which can be stored permanently and moved around. 99% of the time it's a mistake to put a reference inside a struct.
Instead of trying to hold on to a temporarily borrowed slice &'a [f32], store an owned Vec<f32> or an owned slice Box<[f32]>.
If you expect points to have two dimensions, it'd be more efficient to use fields, 2-element array or a tuple (f32, f32). If you want a small, but variable number of dimensions, it's more efficient to use ArrayVec<[f32; 4]>.
This question already has answers here:
How can I borrow from a HashMap to read and write at the same time?
(2 answers)
Closed 2 years ago.
I want move elements of HashSet[0] to HashSet[1], but always encounter borrowed error:
I try using a tmp vec to save the elemetns, but problem still exists:
use std::collections::HashSet;
fn main() {
let mut hsets = vec![];
hsets.push(HashSet::new());
hsets[0].insert("a1");
hsets[0].insert("a2");
hsets.push(HashSet::new());
hsets[1].insert("b1");
hsets[1].insert("b2");
// tmp vec save hsets[0]: [a1, a2]
let mut arr = vec![];
for v in &hsets[0] {
arr.push(v);
}
for v2 in arr {
hsets[1].insert(v2);
}
}
Result:
error[E0502]: cannot borrow `hsets` as mutable because it is also borrowed as immutable
--> src/main.rs:18:9
|
13 | for v in &hsets[0] {
| ----- immutable borrow occurs here
...
17 | for v2 in arr {
| --- immutable borrow later used here
18 | hsets[1].insert(v2);
| ^^^^^ mutable borrow occurs here
error: aborting due to previous error
I'm assuming you don't want to move the HashSets out of the Vec or de-allocate them, in which case you can do this:
use std::collections::HashSet;
fn main() {
let mut hsets = vec![];
// first set
hsets.push(HashSet::new());
hsets[0].insert("a1");
hsets[0].insert("a2");
// second set
hsets.push(HashSet::new());
hsets[1].insert("b1");
hsets[1].insert("b2");
dbg!(&hsets);
assert_eq!(hsets[0].len(), 2);
assert_eq!(hsets[1].len(), 2);
// move elements from first set to second set
let (first, second) = hsets.split_at_mut(1);
second[0].extend(first[0].drain());
dbg!(&hsets);
assert_eq!(hsets[0].len(), 0);
assert_eq!(hsets[1].len(), 4);
}
playground
If you'd like to get a deeper understanding of why your code as-is doesn't compile then read How to get mutable references to two array elements at the same time?.
Try to be explicit about the type of the Vector like
let mut arr: Vec<&str> = vec![]; // otherwise compiler is interpreting as Vec<&&str>
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d0b4e82ab1eb12791a18cf6d33ad0ca4
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?