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.
Related
This question already has an answer here:
What is lifetime elision in very simple terms?
(1 answer)
Closed 3 months ago.
I have this function that borrows two individual elements from a vector. It works as expected:
fn borrow_mut_two<T>(v: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) {
assert!(i < j);
let (left, right) = v.split_at_mut(j);
(&mut left[i], &mut right[0])
}
fn test() {
let mut v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
let i = 2;
let j = 5;
let (ref_a, ref_b) = borrow_mut_two(&mut v, i, j);
*ref_a += 1;
*ref_b += 5;
assert_eq!(*ref_a, i + 1);
assert_eq!(*ref_b, j + 5);
}
What I'm trying to understand is why the following code doesn't compile:
fn test() {
let mut v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
let i = 2;
let j = 5;
let (ref_a, ref_b) = borrow_mut_two(&mut v, i, j);
// Added this line:
let (other_ref_a, other_ref_b) = borrow_mut_two(&mut v, i, j);
*ref_a += 1;
*ref_b += 5;
assert_eq!(*ref_a, i + 1);
assert_eq!(*ref_b, j + 5);
}
It seems it works in a safe manner, because it doesn't allow me to mutably borrow the same elements twice (or potentially other elements).
My question is how does the compiler know that this is unsafe (and therefore reject compiling it)?
The compiler errors are:
229 | let (ref_a, ref_b) = borrow_mut_two(&mut v, i, j);
| ------ first mutable borrow occurs here
230 | let (other_ref_a, other_ref_b) = borrow_mut_two(&mut v, i, j);
| ^^^^^^ second mutable borrow occurs here
As far as I know the return value of borrow_mut_two is the tuple (&mut T, &mut T), which may or may not be a borrow to self, but it seems the compiler does know it's borrowing self. My assumptions may be wrong though 🙂.
The only thing that comes to mind is that Rust automatically adds the lifetime:
fn borrow_mut_two<'a, T>(v: &'a mut [T], i: usize, j: usize) -> (&'a mut T, &'a mut T)
Which would mean that in my test function, 'a is still alive (i.e. self mutably borrowed) due to the first call to borrow_mut_two while the second call happens, and that's how it detects a second mutable borrow.
But I'd like to confirm if this is correct.
Extra
It could be related to this part of the book. The only difference I see is that my function returns a tuple. So the question can be reduced to: Does Rust's second lifetime elision rule also add 'a to each element of a tuple? If so, then my doubt is solved:
The first rule is that the compiler assigns a lifetime parameter to
each parameter that’s a reference. In other words, a function with one
parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32); a
function with two parameters gets two separate lifetime parameters: fn
foo<'a, 'b>(x: &'a i32, y: &'b i32); and so on.
The second rule is that, if there is exactly one input lifetime
parameter, that lifetime is assigned to all output lifetime
parameters: fn foo<'a>(x: &'a i32) -> &'a i32.
Yes, your understanding is correct - due to lifetime elision, the following two function signatures are equivalent:
fn borrow_mut_two<T>(v: &mut [T], i: usize, j: usize) -> (&mut T, &mut T)
fn borrow_mut_two<'a, T>(v: &'a mut [T], i: usize, j: usize) -> (&'a mut T, &'a mut T)
Because the lifetimes of the output are tied to the lifetime of v, the compiler knows that v is still mutably borrowed until those derived references stop being used.
The issue in your second code is that you are trying to borrow mutably v while an other mutable borrow is still alive, just as the compiler indicates to you. To be more precise, the compiler sees the following constraints:
fn test() {
// ...
let (ref_a, ref_b) = borrow_mut_two(&'3 mut v, i, j); // ------+
// ^^^^^ ^^^^^ ^^^^^^^ Let's call // |
// +---+ this lifetime '3 // |
// | // |
// Let's call the lifetime of these mutable borrows '1 // |
// Added this line: // +- '1
let (other_ref_a, other_ref_b) = borrow_mut_two(&'4 mut v, i, j); // -+ '2 |
// ^^^^^^^^^^^ ^^^^^^^^^^^ // | |
// +------+ Let's call the lifetimes of these borrows '2 // -+ |
*ref_a += 1; // |
*ref_b += 5; // ------+
}
First of all, '3 and '4 cannot outlive the lifetime of v, but this isn't very important in this case so we can forget about it. Then, due to the signature of borrow_mut_two, '1='3 and '2='4. Furthermore, since we are talking about mutable borrows, there can be at most one at a time. Finally, I have indicated the minimum span of '1 and '2.
When the compiler tries to enforce all these constraints, it will fail, because clearly '1 and '2 cannot be disjoint while living at least for as much time as they are useful.
In fact, it is sometimes possible to make this kind of layout work, because '1 is never used when '2 is used, and '2's span is included in '1's. In these cases, the compiler says the borrows are stacked, and it could accept them if '2 was a reborrow of '1. It is logically the case, but split_at_mut prevents the compiler from understanding this because internally it uses unsafe code on which the compiler can't reason as easily as it would otherwise.
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()).
In the below code example, I'm trying to increment the member variable a of the struct X via a mutable reference to it, in four different ways. Here, the compiler gives the following error for the line denoted by B:
error[E0502]: cannot borrow `*x` as immutable because it is also borrowed as mutable
--> src\main.rs:17:23
|
17 | *x.get_a_mut() += x.get_a(); //B DOESN'T COMPILE
| ------------------^--------
| || |
| || immutable borrow occurs here
| |mutable borrow occurs here
| mutable borrow later used here
If it is a problem to use a mutable and an immutable reference to a in the same expression, why does C and D compile?
struct X {
a: i64,
}
impl X {
pub fn get_a_mut(&mut self) -> &mut i64 {
return &mut self.a;
}
pub fn get_a(&self) -> &i64 {
return &self.a;
}
}
fn my_fn(x: &mut X) {
*x.get_a_mut() += 5; //A
*x.get_a_mut() += x.get_a(); //B DOESN'T COMPILE
*x.get_a_mut() += 2 * x.get_a(); //C
*x.get_a_mut() = x.get_a() + x.get_a(); //D
}
fn main() {
let mut x = X { a: 50 };
my_fn(&mut x);
}
According to += documentation, you are calling something like add_assign(lhs: &mut i64, rhs: &i64) in case B and something like add_assign(lhs: &mut i64, rhs: i64) in cases A, C and D.
In case A, rhs is a constant, different from x.a; no problem.
In case C, rhs is a temporary (the result of 2 * x.get_a()) and does not need to keep a reference on x.a to exist; no problem.
In case D, rhs is a temporary (the result of x.get_a() + x.get_a()) and does not need to keep a reference on x.a to exist; no problem.
But when it comes to case B, rhs is a reference on x.a; then this call uses both a mutable (lhs) and immutable (rhs) reference on the same data (x.a) at the same time, which is forbidden.
You could eventually clone rhs: *x.get_a_mut() += x.get_a().clone().
I need the trait XYZ to define a method that allows iterating over some set of integers. This set of integers is defined either by a backing Vec or by a Range<usize>. However, I run into various (lifetime or type) issues depending on how I define the XYZIterator type that is supposed to unify these Iterators over Vec/Range.
The backup solution would be to allocate and return Vecs, but I wondered whether there was a way without cloning/allocating memory.
type XYZIterator = Box<dyn Iterator<Item = usize>>;
trait XYZ {
fn stuff(&self) -> XYZIterator;
}
struct Test {
objects: Vec<usize>,
}
impl XYZ for Test {
fn stuff(&self) -> XYZIterator {
Box::new(self.objects.iter())
}
}
struct Test2 {}
impl XYZ for Test2 {
fn stuff(&self) -> XYZIterator {
Box::new((1..4).into_iter())
}
}
fn main() {
let t1 = Test {
objects: vec![1, 2, 3],
};
let t2 = Test2 {};
t1.stuff().for_each(|x| println!("{}", x));
t2.stuff().for_each(|x| println!("{}", x));
t1.stuff()
.filter(|x| x % 2 == 0)
.for_each(|x| println!("{}", x));
t2.stuff()
.filter(|x| x % 2 == 0)
.for_each(|x| println!("{}", x));
}
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, usize> as Iterator>::Item == usize`
--> src/main.rs:12:9
|
12 | Box::new(self.objects.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
|
= note: expected type `usize`
found reference `&usize`
= note: required for the cast to the object type `dyn Iterator<Item = usize>`
Your code has two issues:
In the implementation of XYZ for Test1, you return the iterator self.objects.iter(). Vec::iter iterates over references to the objects, not objects themselves, so this is an iterator over &usize, which doesn't match the return type. You should have gotten an error about this. It's easy to fix though: self.objects.iter().copied() will copy each element out of the reference.
In type XYZIterator = Box<dyn Iterator<Item = usize>>;, since there is no lifetime in the trait object, it defaults to 'static - that is, your iterator can live forever. But that's not the case with the vector iterator - it has a reference to the vector is iterating over. This is where you are having lifetime issues.
The solution is to give the XYZIterator type a lifetime:
type XYZIterator<'a> = Box<dyn Iterator<Item = usize> + 'a>;
And alter the traits and trait implementations to use the lifetime.
Also consider altering your type or function to accept any T: Iterator<Item=usize>; it will then accept any iterator that produces usizes
I want to find the first even number that is not 0. I'm not interested in mutating it, so I thought that this code above would give me an immutable option back:
fn main() {
let first_ten = 0..10;
let val = first_ten.find(|&n| (n % 2 == 0) && n > 0);
println!("{}", val.unwrap());
}
Instead, I get the following error:
--> src/main.rs:3:13
|
2 | let first_ten = 0..10;
| --------- consider changing this to `mut first_ten`
3 | let val = first_ten.find(|&n| (n % 2 == 0) && n > 0);
| ^^^^^^^^^ cannot borrow mutably
I found this documentation page and I see that the predicate is defined as:
P: FnMut(&Self::Item) -> bool,
If I change the definition of first_ten to be let mut first_ten = 0..10, then the code works. Why does first_ten need to have mut?
find is Iterator::find, and that's defined as:
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
The definition of the predicate is irrelevant. The important part is &mut self.
Why is it &mut self and not &self? Because it's defined on Iterator, and the only base method on Iterator (i.e. that implementations must provide) is next, which is:
fn next(&mut self) -> Option<Self::Item>;
The only way you can get the next thing from an Iterator is to mutate it. find doesn't have any choice.
The range has to be mutable because you're using it as an iterator, and iterators have to be mutable to be iterated, and searching an iterator requires iterating it.