Mut iterator and lifetime questions


#1

Hi,

just like a lot of people, I have some issues implementing an iterator that returns mut ref.

Although following code is not doing anything useful, it shows my current compilation issues:
https://play.rust-lang.org/?gist=51db274886c7872106e8de4fa32874f8&version=stable&backtrace=0

At this point I’m usure whether I’m trying something impossible without unsafe code or whether I did not specify the lifetime correctly.


#2

The problem is, with the way Iterator is designed you are able to call next() multiple times and keep around all those references at once. Returning &mut self.mstr multiple times as in the playground example is out of the question.

With slices, for example, that is not a problem since every next() returns a mutable reference to a different element, which can exist at the same time.

So first you need to make sure that you can live with that condition, otherwise you can’t possibly implement a mutable iterator safely.


#3

An iterator that yields references (shared or mutable) is just an intermediate between something that owns/holds the data that is iterated over and the consumer of the iterator elements. So it can not insert itself into that; elements don’t borrow from the iterator.

For example &'x mut [T] can be iterated over using std::slice::IterMut<'x, T>, which yields &'x mut T (references that borrow the slice, not the iterator).

MyStructIterMut does fit into that pattern, but it tries to yield the same mutable reference more than once. That’s not possible, mutable references are exclusive borrows.


#4

thanks for your help it is great. Unfortunately I am still confused, I need to do some more reading on the subject.

Also I have to admit that my first example is not very good.

Here’s another one exemple, perhaps a little closer to what I have in mind.

MyStruct contains a hashmap and I would like to iterate over that hashmap in some custom way and modify it in place.

https://is.gd/dipMvp

I noticed that crate petgraph does not use iterator to iterate and modify a graph in place. but they use some sort of “walker” object. I am wondering wether the author did it that way because of limitations of mut iterators.

https://docs.rs/petgraph/0.4.1/petgraph/graph/struct.WalkNeighbors.html


#5

As the author of that, yes, kind of. If there would be just one way to traverse a graph, there would probably be a more regular Iterator-iterator that yielded mutable references for that. A mutable version of the iterator that yields edge weights wouldn’t be a problem, but that’s just one of the so many ways the data structure could be used (and in many of them you want to mutate some weights while reading others).

The petgraph trade off is that it provides a way to traverse the graph using only indices. All read- or write access to the graph is checked by the borrow checker still, but the guarantee that an index is valid or is still pointing to the same node or edge is lost, so it does not protect against iterator invalidation. (Violations result in logic errors like getting the wrong data or a panic for out of bounds access.)


#6

thanks for the explanation. I think I’m going to use similar approach as well.