Reuse binding in Rust closure - rust

I am attempting to generate a Vec<(Point, f64)>:
let grid_size = 5;
let points_in_grid = (0..grid_size).flat_map(|x| {
(0..grid_size)
.map(|y| Point::new(f64::from(x), f64::from(y)))
.collect::<Vec<Point>>()
});
let origin = Point::origin();
let points_and_distances = points_in_grid
.map(|point| (point, point.distance_to(&origin)))
.collect::<Vec<(Point, f64)>>();
I get the following error:
use of moved value: point
I understand that I cannot use point in both elements of the tuple, but when I attempt to store a reference, I get an error regarding lifetime.

I am presuming your Point struct looks like the following:
#[derive(Debug)]
struct Point(f64, f64);
impl Point {
fn new(x: f64, y: f64) -> Self { Point(x, y) }
fn origin() -> Self { Point(0.,0.) }
fn distance_to(&self, other: &Point) -> f64 {
((other.0 - self.0).powi(2) + (other.1 - self.1).powi(2)).sqrt()
}
}
Now let's look at an even simpler example that will not compile:
let x = Point::new(2.5, 1.0);
let y = x;
let d = x.distance_to(&y);
Which gives the error:
error[E0382]: use of moved value: `x`
--> <anon>:15:13
|
14 | let y = x;
| - value moved here
15 | let d = x.distance_to(&y);
| ^ value used here after move
|
= note: move occurs because `x` has type `Point`, which does not implement the `Copy` trait
Because x has been moved into y, it now can't have a reference taken in order to call the distance_to function.
The important thing to note here is that order matters - if we swap the lines over we can call distance_to by borrowing x, the borrow will end and then x can be moved into y.
let x = Point(0., 0.);
let d = x.distance_to(&y);
let y = x; // compiles
In your case, a very similar thing is happening when constructing the tuple. point gets moved into the tuple, and then tries to borrow it to form the second element. The simplest solution is to do the same thing as here: swap the order of the elements of the tuple.
let points_and_distances = points_in_grid
.map(|point| (point.distance_to(&origin), point))
.collect::<Vec<(f64, Point)>>(); // compiles
Playground link
N.B. if you want to retain the order:
.map(|(a, b)| (b, a))

Related

Why is struct consumed when using self but not when deconsturcting?

I started learning rust from https://doc.rust-lang.org/rust-by-example/, and as far as I understand rust uses move on an assignment, and you explicitly have to tell it to copy with clone().
#[derive(Debug)]
struct Point {
x: f32,
y: f32,
}
impl Point {
fn destroy(self) {
let Point{x, y} = self;
println!("pt is consumed: {}, {}", x, y);
}
}
fn main() {
let pt = Point{x: 2f32, y: 2f32};
let Point{x, y} = pt; //#a
println!("destructured, pt not consumed: {}, {}", x, y);
let pt2 = pt; //#b
//println!("pt is consumed: {:?}", pt);
pt2.destroy(); //#c
//println!("pt2 is consumed: {:?}", pt2);
}
So pt is consumed on #b, that is clear why. But why is it consumed on #c when it's not consumed on #a?
The reason is that, when destructuring the structure, we semantically move its fields out of it one-by-one. But in your case the fields are Copy, so they're copied, not moved, and the struct remains intact.
If you tried with something that's non-Copy, like String, you get the expected error:
error[E0382]: use of partially moved value: `pt`
--> src/main.rs:18:15
|
16 | let Point{x, y} = pt; //#a
| - value partially moved here
17 | println!("destructured, pt not consumed: {}, {}", x, y);
18 | let pt2 = pt; //#b
| ^^ value used here after partial move
|
= note: partial move occurs because `pt.y` has type `String`, which does not implement the `Copy` trait
Playground
Since f32 implement Copy the assignment at #a which could also be written as
let x = pt.x;
let y = pt.y;
performs 2 implicit copies of the two float values and thus doesn't move pt.
But Point::destroy() takes ownership of the Point (by using self instead of &self) and thus moves the Point into it's body.
What it does inside of the function is irrelevant (i.e. you can still use self after let Point{ x, y } = self; but not pt2 after pt2.destroy()).

Explicit lifetime annotations toy example

I'm trying to figure out a Rust lifetime issue and after boiling it down a bunch, I realized that I have no idea how I would explicitly annotate the lifetimes of r, x2, and _arr in foo:
struct X<'a> {
_v: &'a mut i32,
}
fn main() {
let mut v1 = 0;
let x1 = X { _v: &mut v1 };
foo(x1);
}
fn foo(x1: X) {
let mut v2 = 1;
let r = &mut v2;
let x2 = X { _v: r };
let _arr = [x1, x2];
}
I'm going to work off of the assumption that the part of your code that got cut off is the following:
struct X<'a> {
_v: &'a mut i32,
}
In that case, let's dissect what's going on in foo a little bit.
fn foo(x1: X) {
// Lives until the end of the function, call its lifetime 'v2
let mut v2 = 1;
// Borrow v2 for some lifetime 'r which is no longer than 'v2
// so r is of type &'r mut i32
let r = &mut v2;
let x2 = X { _v: r }; // x2 is of type X<'r>
let _arr = [x1, x2]; // ??
}
The confusion probably comes from the fact that x1 seems to have an ambiguous lifetime in its type. This is because we didn't explicitly specify the lifetime in x1: X. This is a Rust 2018 idiom, and I personally recommend not doing this. You can add #![deny(rust_2018_idioms)] to the top of your crate root and the compiler will point out these ambiguities to you and force you to be more explicit. What happens here is that the function declaration gets de-sugared to the following:
fn foo<'x1>(x1: X<'x1>) { ... }
Now it is implied that the lifetime 'x1 extends at least through the body of foo, and this makes sense because it kind of has to. If something which lived for 'x1 was freed in the middle of foo (disregarding how something like that could even happen), then that would defeat the point of using lifetimes for memory safety.
So that being said, let's revisit this line:
let _arr = [x1, x2];
We know that x2 is of the type X<'r> and that 'r extends at most to the end of foo (since 'r is no longer than 'v2 and 'v2 extends to the end of foo). Moreover, we know that x1 is of the type X<'x1> and that 'x1 extends at least to the end of foo. This means that 'x1 is at least as long as 'r. Since lifetimes are covariant, this means that X<'x1> is a sub-type of X<'r>, since whenever we require a value of the type X<'r> we can safely substitute in one of type X<'x1> instead. So what happens is _arr is given the type [X<'r>; 2], and upon construction the lifetime on x1 is shortened to 'r.
We can actually test this hypothesis to see if it's correct. What would happen if the compiler wasn't allowed to shorten that lifetime? In other words, what if the lifetime on X was not covariant. If we modify X as follows then its lifetime type parameter is made invariant:
struct X<'a> {
_v: &'a mut i32,
_invariant: PhantomData<fn(&'a ()) -> &'a ()>
}
And sure enough, after adding the _invariant field in the appropriate places to make the code compile, we receive the following error:
|
14 | fn foo<'x1>(x1: X<'x1>) {
| --- lifetime `'x1` defined here
15 | let mut v2 = 1;
16 | let r = &mut v2;
| ^^^^^^^ borrowed value does not live long enough
17 | let x2 = X { _v: r, _invariant: PhantomData };
| - this usage requires that `v2` is borrowed for `'x1`
18 | let _arr = [x1, x2];
19 | }
| - `v2` dropped here while still borrowed
Now how do we know the compiler wasn't extending the lifetime 'r to 'x1 in the first place? Well if it was doing that, then we could modify foo to do the following, which would unequivocally cause a use-after-free:
fn foo<'x1>(x1: X<'x1>) -> &'x1 mut i32 {
let mut v2 = 1;
let r = &mut v2;
let x2 = X { _v: r };
let _arr = [x1, x2];
_arr[1]._v
}
And sure enough if you try the code above it fails to compile with the reason given being that we're returning a reference to a local variable. Moreover, if you try returning _arr[0]._v, then you get the exact same error.
Sub-typing and variance can be pretty hard to grasp and it's not something you need to fully understand to be an effective Rust programmer. Nonetheless, it is very interesting and you can learn more about it here in the Rustonomicon.

Why is the compiler letting me borrow another borrow in a box?

I'm wondering if someone can help me understand why this program behaves as it does:
fn main() {
let mut x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&mut y);
println!("GOT {}",*y);
}
}
This program compiles under rust 1.35.0 (both 2015 and 2018 editions), and prints
GOT 456
But, I'm confused what's going on here. I'm guessing that this is an example of an auto-dereference. So, in reality, it looks like this:
fn main() {
let mut x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&mut *y);
println!("GOT {}",*y);
}
}
Is that it?
This is a case of deref coercion, but one that is obfuscated by a few other unnecessary parts of the code. The following improvements should be made here:
The mut modifier on variable x is not needed because it is never modified.
The borrow of y in Box::new(&mut y) does not have to be mutable because the variable holds an immutable reference.
The println! implementation also knows to print values behind references, so the explicit * is not needed.
Then, we get the following code:
fn main() {
let x = 456;
{
let mut y = Box::new(&x);
y = Box::new(&y);
println!("GOT {}", y);
}
}
y is a variable of type Box<&i32> which is initially bound to a box created in the outer scope. The subsequent assignment to a new box works because the &y, of type &Box<&i32>, is coerced to &&i32, which can then be put in the box by automatically dereferencing the first borrow. This coercion is required because the variable x can only be assigned values of the same Box<&i32> type.
The lifetime of the reference inside both boxes also ended up being the same, because they refer to the same value in x.
See also:
What is the relation between auto-dereferencing and deref coercion?

Why is there a borrow of a moved value when calling a method that takes self by value with an argument that also calls a method?

I ran into an issue that forces me to split a nice oneliner into a {} block with an intermediate let. The reason for this isn't clear to me at all. I was able to isolate the issue in this minimal example:
struct AB {
a: u8,
b: u8,
}
impl AB {
fn foo(&self) -> String {
String::from("foo")
}
fn bar(self, x: String) -> String {
format!("{} - {} - {}!", x, self.a, self.b)
}
}
fn main() {
let x = AB { a: 3, b: 5 };
let result = x.bar(x.foo());
println!("{}", result);
}
I was under the impression that the arguments to the bar function would be evaluated before calling bar. foo borrows x during its execution, but when it returns its String, the borrow is finished, as String is not a reference bearing x's lifetime. When bar gets called, foo's borrow should be over.
However, the compiler disagrees:
error[E0382]: borrow of moved value: `x`
--> src/main.rs:17:24
|
17 | let result = x.bar(x.foo());
| - ^ value borrowed here after move
| |
| value moved here
|
= note: move occurs because `x` has type `AB`, which does not implement the `Copy` trait
I'm not disagreeing with the fact that bar indeed moves x. My issue is with the statement that foo borrows x after the move takes place.
A simple (but ugly) fix:
struct AB {
a: u8,
b: u8,
}
impl AB {
fn foo(&self) -> String {
String::from("foo")
}
fn bar(self, x: String) -> String {
format!("{} - {} - {}!", x, self.a, self.b)
}
}
fn main() {
let x = AB { a: 3, b: 5 };
let y = x.foo();
let result = x.bar(y);
println!("{}", result);
}
separating the assignment of x.foo() to an intermediate variable y compiles fine, confirming my expectation that the borrow is indeed over once foo returns, but why does this work? Is there something I don't understand about evaluation order? Why can't I get rid of the intermediate let y ?
Evaluation order, for the purpose of borrows, is from left to right.
This means that the subject of the bar call, the "move-out" mention of x, is considered before the "borrow" mention of x in the foo call, and therefore, the compiler considers the variable to have been moved from.
For the similar case where the outer mention is a mutable borrow, RFC 2025 has been accepted as a solution, but hasn't been implemented yet. Unfortunately this RFC doesn't appear to cover your case, where the outer use is a move.

Type inference and borrowing vs ownership transfer

I am learning Rust and I've run into some confusing behaviour. The following code compiles fine and works as expected (edit: added code other than test function, previously omitted):
struct Container<'a> {
contents : &'a mut i32,
}
fn main() {
let mut one = Container { contents: &mut 5 };
test(&mut one);
println!("Contents: {}",one.contents);
}
fn test<'a>(mut x : &'a mut Container) {
*x.contents += 1;
let y = x;
*y.contents += 1;
x = y;
println!("{:?}",*x.contents)
}
Now in the statement
let y = x;
the type is inferred. Because x is of type &'a mut Container, I thought that this would be equivalent:
let y: &'a mut Container = x;
But when I do that, the compiler takes issue:
test_3.rs:25:5: 25:10 error: cannot assign to `x` because it is borrowed
test_3.rs:25 x = y;
^~~~~
test_3.rs:23:33: 23:34 note: borrow of `x` occurs here
test_3.rs:23 let y: &'a mut Container = x;
How is x not borrowed by that point in the correctly working example? I tested by omitting the line x = y; from the correctly working version and the compiler said:
test_3.rs:24:13: 24:14 note: `x` moved here because it has type `&mut Container<'_>`, which is moved by default
So I'm getting a move when I don't explicitly define the type but a borrow otherwise. What is going on, how do I get the same behavior as before while explicitly giving the type, and what is causing move behavior in one case but borrow in the other?
Edited with full program
When you do
let y = x;
a move happens. x is emptied, so to speak, and ownership is transferred to y.
When you do either of
let y: &mut _ = x;
let y: &'a mut _ = x;
x is reborrowed to aid matching the lifetimes. This roughly translates to
let y: &mut _ = &mut *x;
let y: &'a mut _ = &mut *x;
This leaves x non-empty, holding an aliased mutable borrow. Assigning to it thus must wait for y to be destroyed. Alternatively, you can pre-move it
let tmp = x;
let y: &'a mut _ = tmp;
I'll admit it's nonobvious behaviour, and it's a shame that you can't borrow the contents of a value without borrowing the whole value.

Resources