2
votes

I'm having trouble with the borrow checker not "releasing" a mutable borrow.

I have:

let mut data = (1..=100).collect::<Vec<_>>();
let mut c = Canvas::new(10, 10, &mut data);


c.iter_rows_mut(4..7);
c.iter_rows(4..7).collect::<Vec<_>>();

And it's complaining:

error[E0502]: cannot borrow `c` as immutable because it is also borrowed as mutable
  --> src/lib.rs:59:9
   |
57 |         c.iter_rows_mut(4..7);
   |         - mutable borrow occurs here
58 | 
59 |         c.iter_rows(4..7).collect::<Vec<_>>();
   |         ^
   |         |
   |         immutable borrow occurs here
   |         mutable borrow later used here

error: aborting due to previous error

I can understand the problem if I was handing onto a reference related to the mutable call, but that doesn't appear to be the case.

Rust Playground with full code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=de4143ddf57cc8a97e7a884bbe13dfa4

1

1 Answers

4
votes

The problem here is in the lifetime annotations. You're using the same lifetime 'd throughout, so the mutable borrow in c.iter_rows_mut has to last the entire lifetime of c.

To fix this, use a different lifetime in iter_rows and iter_rows_mut. It'll be implicitly bound to be no longer than 'd, but it'll allow more flexibility.

The fully explicit signatures should be

fn iter_rows<'a>(&'a self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &'a [T])> + 'a

and

fn iter_rows_mut<'a>(&'a mut self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &'a mut [T])> + 'a {

Thanks to lifetime elision, though, we don't need any of those lifetimes. All the lifetimes in the output type will be implicitly the same as the lifetime on &self (or &mut self).

fn iter_rows(&self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &[T])>
fn iter_rows_mut(&mut self, vertical_range: Range<usize>) -> impl Iterator<Item=(usize, &mut [T])>

(playground)

P.S. The into_iter calls in each of these functions aren't necessary: chunks_exact already produces an iterator. Clippy warns about this.