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()).
Related
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.
I am trying to express the following:
Given a matrix and two index increments, return all quadruplets of numbers from the matrix: quadruplets of numbers along the rows, or along the columns, or along some diagonal.
use std::iter::Iterator;
use std::iter::Peekable;
use std::ops::Range;
struct Quads<'a> {
mx: &'a Vec<Vec<u32>>,
xs: &'a mut Peekable<Range<i32>>,
ys: &'a mut Peekable<Range<i32>>,
dx: i32,
dy: i32,
}
impl<'a> Quads<'a> {
fn new(mx: &'a Vec<Vec<u32>>, dx: i32, dy: i32) -> Quads<'a> {
let ys = (if dy < 0 { -3 * dy } else { 0 })..(mx.len() as i32 - if dy > 0 { 4 * dy } else { 0 });
let xs = 0..0;
Quads{
mx: mx,
xs: &mut xs.peekable(),
ys: &mut ys.peekable(),
dx: dx,
dy: dy,
}
}
}
impl<'a> Iterator for Quads<'a> {
type Item = &'a mut dyn Iterator<Item = u32>;
fn next(&mut self) -> Option<Self::Item> {
while self.xs.peek() == None && self.ys.peek() != None {
self.xs = &mut ((if self.dx < 0 { -3 * self.dx } else { 0 })..
(self.mx[0].len() as i32 - if self.dx > 0 { 4 * self.dx } else { 0 }))
.peekable();
self.ys.next();
}
let y = self.ys.peek();
if y == None {
return None;
}
let y = *y.unwrap();
let x = self.xs.next().unwrap();
Some(&mut ((x..).step_by(self.dx as usize)
.zip((y..).step_by(self.dy as usize))
.take(4)
.map(|(x,y)| self.mx[y as usize][x as usize])))
}
}
This produces confusing error messages:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:52:27
|
52 | .map(|(x,y)| self.mx[y as usize][x as usize])))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 33:4...
--> src/main.rs:33:4
|
33 | / fn next(&mut self) -> Option<Self::Item> {
34 | | while self.xs.peek() == None && self.ys.peek() != None {
35 | | self.xs = &mut ((if self.dx < 0 { -3 * self.dx } else { 0 })..
36 | | (self.mx[0].len() as i32 - if self.dx > 0 { 4 * self.dx } else { 0 }))
... |
52 | | .map(|(x,y)| self.mx[y as usize][x as usize])))
53 | | }
| |____^
= note: ...so that the types are compatible:
expected &&mut Quads<'a>
found &&mut Quads<'a>
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 30:6...
--> src/main.rs:30:6
|
30 | impl<'a> Iterator for Quads<'a> {
| ^^
= note: ...so that the types are compatible:
expected std::iter::Iterator
found std::iter::Iterator
It seems to indicate that it has found the same things it was looking for. So what's wrong?
Intended use
Look at https://projecteuler.net/problem=11
Of course, that problem can be solved in more straightforward ways, but I am learning how to express complex things in Rust. So here I am trying to express a Quad that is an Iterator that can extract quadruples of numbers from that Euler problem, where each quadruple is an Iterator itself.
Everything inside Quad represents the state of the Iterator. xs and ys represent the iterators of the coordinates of "the current cell" from which to start the next quadruple. next then tries to see if reached the end of the row, and advances to the next row by reinitialising xs to a new Iterator. When ys reached beyond the last row, we've extracted all the quadruples.
Then something like this:
for q in Quad::new(mx, 1, 0) { ... process all quadruples along the rows }
for q in Quad::new(mx, 0, 1) { ... process all quadruples along the columns }
for q in Quad::new(mx, 1, 1) { ... process all quadruples along one diagonal }
for q in Quad::new(mx, 1, -1) { ... process all quadruples along the other diagonal }
I think I've got the idea captured, but I don't know what the compiler does not like about it, and consequently how to move forward.
Ok, so I figured it out. It is really not helpful that rustc produced such a confusing error message - evidently, it found what it was looking for, but still unsatisfied.
There are several problems with the code as posted. My original assumption has been that by marking a reference as mutable I can tell the compiler that whoever receives the reference is responsible for it henceforth, including memory management. Whereas it may be true in some cases (I am not certain; that's still to figure out), it certainly does not work with struct fields (Quad's xs) and return values. In this case we can get rid of &mut in the declaration of the xs and ys:
struct Quads<'a> {
mx: &'a Vec<Vec<u32>>,
xs: Peekable<Range<i32>>,
ys: Peekable<Range<i32>>,
dx: i32,
dy: i32,
}
The other problem has been that if it is not a reference, how do you limit the lifetime of a value. (Eg in this case the Iterator returned by next is valid only for as long as the mx)
The other problem has been the expression problem: how do you make next return an Iterator (I don't want to leak what kind of Iterator) so that the compiler is happy. (Eg just dyn Iterator won't do - "size is not known at compile time"). These two are solved by using Box, which can be annotated with a lifetime, too:
impl<'a> Iterator for Quads<'a> {
type Item = Box<dyn Iterator<Item = u32> + 'a>;
fn next(&mut self) -> Option<Self::Item> {
...
}
}
The other problem has been that even though the use of mx is read-only, the closure |(x, y)| self.mx[y][x] captures self, which is a mutable reference. That's the easy one: get a local variable, then move:
let mx = self.mx;
Some(Box::new(...
.map(move |(x, y)| mx[y as usize][x as usize])))
Nearly forgot. And the really strange one, which looked fishy even as I typed it originally: step_by takes usize, which is unsigned, and isn't really constructing a Range that enumerates values by adding a given increment; rather it constructs an Iterator that skips a given number of elements (pretty much). So, a tuple iterator is needed:
struct Tup<T> {
x: (T, T),
d: (T, T),
}
...
impl<T: AddAssign + Copy> Iterator for Tup<T> {
type Item = (T, T);
fn next(&mut self) -> Option<(T, T)> {
self.x.0 += self.d.0;
self.x.1 += self.d.1;
Some(self.x)
}
}
So instead of zipping two Iterators with step_by, you get a Tup initialised with known initial values and deltas:
Some(Box::new(Tup::new((x, y), (self.dx, self.dy))
.take(4)
.map(move |(x, y)| mx[y as usize][x as usize])))
Another solution would be not to export iterators, but pass an operation to run inside.
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.
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))
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.