Here is the definition of the Iterator
trait in Rust, just including the one method that must be implemented (the other methods have default implementations, though they can be overridden if there's a more efficient way to do them; I've elided many irrelevant details below):
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
Item
can be any type; and in particular, over many collections, you can choose to either get an iterator over owned items, immutably borrowed items, or mutably borrowed items. Here's the IntoIterator
implementation for Vec
that yields owned items:
impl<T> IntoIterator for Vec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(mut self) -> IntoIter<T> { ... }
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<T> { ... }
}
There are also the iter
and iter_mut
method on slices (and you can call on Vec
because Vec
derefs to a slice) which give you iterators over immutable or mutable references:
fn iter(&self) -> Iter<T> { ... }
fn iter_mut(&mut self) -> IterMut<T> { ... }
Where those types implement the Iterator
trait like so:
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> { ... }
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<&'a mut T> { ... }
}
So, if by "leak a mutable reference", you mean that you can get mutable references during iteration, and save them somewhere else, then yes, you can do that:
fn main() {
let mut v = vec![1, 2, 3];
let mut n: Option<&mut i32> = None;
v.iter_mut().map(|x| n = Some(x)).count();
let x = n.unwrap();
*x += 1;
println!("{}", x);
}
So as you can see, you can indeed borrow in an iterator.
Actually, Rust used to have what Oleg calls enumerables as its primary form of iteration. In the Rust lexicon, the terminology has generally been to refer to them as "internal" vs. "external" iteration, where "internal" iteration is what Oleg refers to as enumerables, and "external" is what he refers to as cursors (in Rust, there's another concept called Cursors that has been discussed but never implemented, which is like a somewhat more flexible iterator that can go forwards and backwards but then can only act by reference rather than being able to consume the collection like iterators can). You should probably read this thread about the reasons for the switch from internal to external iteration, and in particular this message which explains the reasoning.
It turns out that in Rust, external iteration is a lot easier to make work with the borrow checker, works better with code that does things like early return from loops, and is more efficient and easier to optimize.
The downsides are discussed there too, in particular the greater difficulty of implementing external iteration, as you have to write a struct by hand that encapsulates the state. Python or C# style generators with a yield
keyword would make this easier; the idea has been tossed around, some people have experimented with compiler plugins for doing so.