Segregated copy for nested closures - rust

I looked for similar questions like this one but it seems they are always different enough. I'm trying to compile (a more complex version of) this piece of code:
let vec: Vec<f64> = ⋯;
let length = ⋯;
let iterator = (0usize..length)
.flat_map(|i| (0usize..length).map(|j| vec[(i + j) % vec.len()]));
but I get this ownership error:
error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function
--> tests\test.rs:19:45
|
19 | .flat_map(|i| (0usize..length).map(|j| vec[(i + j) % vec.len()]));
| ^^^ - `i` is borrowed here
| |
| may outlive borrowed value `i`
|
I do not want to take ownership of vec so none of my closures should be move. It seems to me that theoretically i could be copied inside (0usize..length).map(|j| vec[(i + j) % vec.len()]) but because of vec it is only borrowed. As far as I know it may not be possible to tell rustc to borrow some variables and to copy others (Or is it?)
Changing the inner closure to (0usize..length).map(|j| vec[(i + j) % vec.len()]).collect::<Vec<_>>() solves the issue. Unfortunately it implies multiple memory allocation I would like to avoid as they seem totally unnecessary.
As a clarification this example is intended to be generated by a macro. In the general case it may generate an arbitrary number of nested levels and involve an arbitrary number of vectors to borrow:
let vec: Vec<f64> = ⋯;
let vec2: Vec<Vec<Vec<f64>>> = ⋯;
let length = ⋯;
let iterator = (0usize..length)
.flat_map(|i| (0usize..length)
.flat_map(|j| (0usize..length)
.map(|k| vec[(i + j + k) % vec.len()] + vec2[i][j][k]));

You must use move to avoid the issue with i. If you don't want to move the vec into the closure, you can take a reference to it first and move that into the closure:
let iterator = (0usize..length)
.flat_map (|i| {
let vec = &vec[..];
(0usize..length).map(move |j| vec[(i + j) % vec.len()])
});
Playground

Related

About the change of the ownership of the array and vec

This code causes a error. It seems reasonable, because the ownership has moved:
fn main() {
let mut arr = vec![1, 2];
let mut arr2 = vec![2, 6];
arr = arr2;
arr2[1] = 2;
}
error[E0382]: borrow of moved value: `arr2`
--> src/main.rs:5:5
|
3 | let mut arr2 = vec![2, 6];
| -------- move occurs because `arr2` has type `Vec<i32>`, which does not implement the `Copy` trait
4 | arr = arr2;
| ---- value moved here
5 | arr2[1] = 2;
| ^^^^ value borrowed here after move
This code won't cause an error:
fn main() {
let mut arr = [1, 2];
let mut arr2 = [2, 4];
arr = arr2;
arr2[1] = 2;
}
This will cause an error:
fn main() {
let mut arr = ["1".to_string(), "2".to_string()];
let mut arr2 = ["2".to_string(), "4".to_string()];
arr = arr2;
arr2[1] = "2".to_string();
}
error[E0382]: use of moved value: `arr2`
--> src/main.rs:5:5
|
3 | let mut arr2 = ["2".to_string(), "4".to_string()];
| -------- move occurs because `arr2` has type `[String; 2]`, which does not implement the `Copy` trait
4 | arr = arr2;
| ---- value moved here
5 | arr2[1] = "2".to_string();
| ^^^^^^^ value used here after move
This works fine...
fn main() {
let mut arr = ["1", "2"];
let mut arr2 = ["2", "4"];
arr = arr2;
arr2[1] = "2";
}
I am completely confused.
In Rust all types fall into one of two categories:
copy-semantic (if it implements the Copy-trait)
move-semantic (if it does not implement the Copy-trait)
These semantics are implicitly employed by Rust whenever you e.g. assign a value to a variable. You can't choose it at the assignment. Instead, it depends only on the type in question. Therefore, whether a in the example below is moved or copied, depends entirely on what T is:
let a: T = /* some value */;
let b = a; // move or copy?
Also notice, that generic types are rather a set of similar types, than a single type by themselves (i.e. it is not a concrete type). For instance, you can't tell whether [T;2] is Copy or not, since it is not a concrete type (would need to know T first). Thus, [&str;2] and [String;2] are two totally different concrete types, and consequently one can be Copy and the other not.
To further elaborate, a concrete type can only be Copy if all constituting types are Copy. For instance, arrays [T;2] might be Copy (if T is too), Vec may never be Copy (independent of T).
So in your examples, when it does not compile due to move-semantics, you either have a Vec that is not Copy or String that is not, and any combinations with them can not be Copy either. Only if you combine Copy-types (arrays, ints, &str) you get copy-semantics, and your examples compile.
Also, this not an issue about ownership, because if you have copy-semantics you can just generate new values (by coping them) wherever you need, which gives you (fresh) ownership of these new values.
Couple of things here. First of all you are not changing the ownership in the working examples. You are merely borrowing their values. The difference in your not working examples is that in them you are actually changing the ownership.
As #eggyal correctly pointed out String and Vec don't implement Copy and that's important because Copy is used automatically when assigning another variable to a new variable. and in your working examples you have i32 (default for numeric types) and &str(also known as a string slice) which both implement Copy.
Every string literal is initially a &str and not a String. The .to_string() method in your example converts a &str into a String. If you want more in-depth information about the differences between &str and String I suggest you either check this answer or read an article about it but what's most important in your case is that string slices point to a read-only portion of the memory making them effectively immutable and therefore safe for copying.
The compiler nowadays is so good that it tells you the entire story. I compiled your code and got this wonderful error message:
|
18 | let mut a = vec![2, 4];
| ----- move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
19 | let b = a;
| - value moved here
20 | println!("{:?}", a);
| ^ value borrowed here after move

Why is iterating over a collection via `for` loop considered a "move" in Rust?

I have the below Rust program.
fn main() {
let v = vec![100, 32, 57];
for i in v {
println!("{}", i);
}
println!("{:?}", v);
}
When I run it, I get:
error[E0382]: borrow of moved value: `v`
--> src\main.rs:7:22
|
2 | let v = vec![100, 32, 57];
| - move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 | for i in v {
| -
| |
| value moved here
| help: consider borrowing to avoid moving into the for loop: `&v`
...
7 | println!("{:?}", v);
| ^ value borrowed here after move
The error states that there is a move happened at for i in v. But I'm just using the same variable v defined by let v = vec![100, 32, 57]. It's not something like let v2 = v; for i in v2 ..., which moved the value from v to v2. Could anyone help to explain a little bit?
As https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops says,
A for expression is a syntactic construct for looping over elements provided by an implementation of std::iter::IntoIterator.
Vec implements IntoIterator, allowing you to own a Vec instance’s elements by consuming it:
Creates a consuming iterator, that is, one that moves each value out of the vector (from start to end). The vector cannot be used after calling this.
(As the error message notes, the way to fix this is to loop over &v instead of v, borrowing its elements instead of owning them. You can loop for &i in &v to maintain the type of i.)
It might seem unnecessary at a high level for you to own the elements of v, since they’re copyable, but there’s no special implementation allowing that information to be used here. IntoIterator.into_iter() takes self, meaning a for loop always consumes the value being iterated over.

Why is indexing a mutable vector based on its len() considered simultaneous borrowing?

I know the general answer — You can only borrow mutably once or immutably many times, but not both. I want to know why this specific case is considered simultaneous borrowing.
I have the following code:
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
let n = 3;
// checks on n and v.len() and whatever else...
let mut s = v[..n].to_vec();
for i in 0..n {
v[i + v.len() - n] = s[1];
}
}
which produces the following error under 1.36.0:
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:7:15
|
7 | v[i + v.len() - n] = s[1];
| ------^-----------
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
It seems that there is no way for the write to v[x] to happen until x is computed, by which time the immutable borrow will be complete. Since the ordering here is completely in series, why doesn't the compiler recognize the dependency and treat these as non-overlapping borrows? Put another way, is there any scenario where this could lead to an actual problem?
Marouane Fazouane suggested concurrency as a possibility, but I don't think this is the case. If there were another thread with a (presumably) mutable reference, it would be a violation to then call v.len(), or to start v[...]. Here, the compiler knows everything that's happening to v — it's a local definition with no other calls. For me, the question is why is this simultaneous borrowing when there's no way for v[] to happen until len() returns. It's akin to v.mutable_call(v.immutable_call());
Incidentally, an earlier version of the compiler (1.28) gave an error that indicated the close bracket as the end of the mutable borrow, so it seemed order is based on the source order, and since the source has the two intermingled, they could be considered overlapping. If so, surely the compiler could improve this...right?
This seems closely related to Why is there a borrow error when no borrowing overlap is occurring?
If so, surely the compiler could improve this...right?
Indeed, NLL intentionally started conservatively, as explained in #494341.
Extracting the temporary allows it to compile:
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
let n = 3;
// checks on n and v.len() and whatever else...
let s = v[..n].to_vec();
for i in 0..n {
let index = i + v.len() - n;
v[index] = s[1];
}
}
This makes it clear that the issue is strictly one of not computing the index before attempting to use it.
Since it is not possible to start the call to IndexMut<Idx>::index_mut(&mut self, index: Idx) before computing the Idx, there is no reason to start the mutable borrow of v before computing the index.
1 Courtesy of trentcl.

Why is `ref mut` on a for loop binding not the same as `&mut` on the variable being looped over?

In Rust by Example, it says:
A ref borrow on the left side of an assignment is equivalent to an & borrow on the right side.
I thought these two for loops would be equivalent:
Compiles successfully:
let mut v2 = vec![1, 2, 3];
for i in &mut v2 {
*i = *i + 1;
}
println!("{:?}", v2);
Does not compile:
let mut v1 = vec![1, 2, 3];
for ref mut i in v1 {
*i = *i + 1;
}
println!("{:?}", v1);
It seems v is moved:
error[E0382]: use of moved value: `v1`
--> src/main.rs:6:22
|
3 | for ref mut i in v1 {
| -- value moved here
...
6 | println!("{:?}", v1);
| ^^ value used here after move
|
= note: move occurs because `v1` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
What you quote from the book is a rule for normal assignments such as those by let. For example:
let x = &42;
let ref x = 42;
But the name binding in a for loop is a bit different:
The value to be looped around is converted into an iterator (<v1 as IntoIterator>::into_iter()) Lets call the result of that it.
Then the it.next() is called repeatedly:
If it returns Some(_) then the value of that is bound to your variable. Just as if you wrote let Some(ref mut i) = it.next() or let Some(mut i) = it.next(). Here is where the ref matters.
If it returns None the loop ends.
So in the for loop case, the ref and the & are not equivalent.
When you use the & at the right side of a loop, it does not change the binding of the variable directly; you just change the type of the object iterated. Then, all comes down to the implementation of IntoIterator for Vec<_> vs that for &Vec<_>.
If you iterate Vec<T>, it takes ownership of the vector and the iteration returns the values themselves. So for i in v1 consumes the vector and the i has the type of the contained values T.
If you iterate &Vec<T>, it borrows the vector and the iteration return pointers to the contained values &T, so in for i in &v1 the type of i is actually a pointer to the values. The same effect can be got with for i in v1.iter().
If you iterate &mut Vec<T>, is just like the previous one but mutable, so the iteration returns values of type &mut T.
The conclusion is that using ref in a for loop is not probably so useful.

Why can I force reference move semantics for `&self` parameter of method, but not function parameters?

I have two versions of a function that are intended to do the same thing.
Version 1 - Works!
pub fn example1() {
// Make a mutable slice
let mut v = [0, 1, 2, 3];
// Make a mutable reference to said slice
let mut v_ref = &mut v[..];
let len = v_ref.len();
// Reduce slice to sub-slice -> np ;)
v_ref = {
// Create sub-slices
let (v_l, v_r) = {
// Involves some edits -> need mut
v_ref.swap(0, len - 1);
{ v_ref }.split_at_mut(len / 2)
};
// Choose slice with which to overwrite
// (involves some non-trivial condition here)
match len % 2 {
0 => v_l,
_ => v_r,
}
};
// And then we do something with v_ref
println!("{:?}", v_ref);
}
Essentially:
We start with a mutable variable, mut v_ref: &mut [i32], containing a mutable reference to a slice
We make two sub-slices from v_ref using split_at_mut*
The variable v_ref is overwritten to hold one of the sub-slices
*(Note - We avoid the problem of having two mutable references by moving v_ref, as opposed to reborrowing, by using an identity block)
(Regarding the intent of the code - this slice reduction is intended to be repeated in a loop; however this detail does not affect the problem)
Version 2 - Fails to compile
Version 2 is nearly identical to version 1, except that the sub-slice creation is moved to its own function:
fn example2_inner(v_ref: &mut [i32]) -> (&mut [i32], &mut [i32]) {
// Recreate len variable in function scope
let len = v_ref.len();
// Same mutation here
v_ref.swap(0, len - 1);
// Same slice split here
v_ref.split_at_mut(len / 2)
}
pub fn example2() {
let mut v = [0, 1, 2, 3];
let mut v_ref = &mut v[..];
let len = v_ref.len();
// This now fails to compile :(
v_ref = {
// Mutating & slice spliting moved to function
let (v_l, v_r) = example2_inner({ v_ref });
match len % 2 {
0 => v_l,
_ => v_r,
}
};
println!("{:?}", v_ref);
}
When I try to build this, I get the following errors:
error[E0506]: cannot assign to `v_ref` because it is borrowed
--> src/lib.rs:19:5
|
19 | / v_ref = {
20 | | // Mutating & slice spliting moved to function
21 | | let (v_l, v_r) = example2_inner({ v_ref });
| | ----- borrow of `v_ref` occurs here
22 | |
... |
26 | | }
27 | | };
| |_____^ assignment to borrowed `v_ref` occurs here
error[E0502]: cannot borrow `v_ref` as immutable because `*v_ref` is also borrowed as mutable
--> src/lib.rs:29:22
|
21 | let (v_l, v_r) = example2_inner({ v_ref });
| ----- mutable borrow occurs here
...
29 | println!("{:?}", v_ref);
| ^^^^^ immutable borrow occurs here
30 | }
| - mutable borrow ends here
Questions
Why don't these two examples compile the same way? Are mutable reference move semantics (i.e., the {vref} from E1) enforced for methods (i.e. split_at_mut), but not functions (i.e., example2_inner)? Why is this the case?
I would like to keep example2_inner as an independent utility function: how would I change Example 2 to accommodate that?
You can fix it like this:
v_ref = {
// move `v_ref` to a new variable which will go out of scope by the end of the block
let r = v_ref;
// Mutating & slice splitting moved to function
let (v_l, v_r) = example2_inner(r);
match len % 2 {
0 => v_l,
_ => v_r,
}
};
The reason is that v_1 and v_2 both are references to v_ref, but these references both outlive the block because they are being returned from it. Then you try to write to v_ref, which the borrow checker doesn't like because there are still these live references around.
Assigning v_ref to a new variable, r, means that v_ref is no longer valid - the variable has been moved. The live references, v_1 and v_2 are now referring to r, which in turn is a reference to v, and which only lives as long as the block. You are now free to write to v_ref because nothing else is referring to it.
Alternatively, you can just update to Rust Edition 2018, or enable non-lexical lifetimes, which can handle this situation.
Why don't these two examples compile the same way? Are mutable
reference move semantics (i.e., the {vref} from E1) enforced for
methods (i.e. split_at_mut), but not functions (i.e., example2_inner)?
Why is this the case?
Actually, it is not about methods vs functions, but about method call syntax vs function call syntax.
Every method call can be translated into the UFCS (Universal Function Call Syntax) which is generally of this form:
<Type as Trait>::method(args);
If we make a naive attempt to translate the call of { v_ref }.split_at_mut(len / 2) into UFCS in version 1, we end up with the same error as in version 2:
<[_]>::split_at_mut({v_ref}, len / 2)
The reason is that the above is equivalent to something which again does not cause v_ref to be moved into the block:
<[_]>::split_at_mut({&mut *v_ref}, len / 2)
What the method syntax actually resolves to is this working variant of the above:
<[_]>::split_at_mut(&mut *{v_ref}, len / 2)
For this variant, the compiler infers that v_ref indeed should be moved into the block, because the compiler realizes that the re-borrowing necessary for the method call is already going to happen on {v_ref}, so it doesn't insert an additional superfluous re-borrow on v_ref.
Now that we know how the method syntax solves your issue implicitly, we have an alternative solution for your issue in version 2:
example2_inner(&mut *{ v_ref });

Resources