auto merge of #9634 : blake2-ppc/rust/by-ref-iter, r=thestinger

std::iter: Introduce .by_ref() adaptor

Creates a wrapper around a mutable reference to the iterator.

This is useful to allow applying iterator adaptors while still
retaining ownership of the original iterator value.

Example::

    let mut xs = range(0, 10);
    // sum the first five values
    let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
    assert!(partial_sum == 10);
    // xs.next() is now `5`
    assert!(xs.next() == Some(5));

---

This adaptor requires the user to have good understanding of
iterators or what a particular adaptor does. There could be some
pitfalls here with the iterator protocol, it's mostly the same issues
as other places regarding what happens after the iterator
returns None for the first time.

There could also be other ways to achieve the same thing, for
example Implementing iterator on `&mut T` itself:
`impl <T: Iterator<..>> Iterator for &mut T`  but that would only
lead to confusion I think.
This commit is contained in:
bors 2013-10-16 17:01:30 -07:00
commit 63e097d8c3

View File

@ -405,6 +405,25 @@ pub trait Iterator<A> {
Inspect{iter: self, f: f}
}
/// Creates a wrapper around a mutable reference to the iterator.
///
/// This is useful to allow applying iterator adaptors while still
/// retaining ownership of the original iterator value.
///
/// # Example
///
/// ```rust
/// let mut xs = range(0, 10);
/// // sum the first five values
/// let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
/// assert!(partial_sum == 10);
/// // xs.next() is now `5`
/// assert!(xs.next() == Some(5));
/// ```
fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> {
ByRef{iter: self}
}
/// An adaptation of an external iterator to the for-loop protocol of rust.
///
/// # Example
@ -771,6 +790,22 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
}
}
/// A mutable reference to an iterator
pub struct ByRef<'self, T> {
priv iter: &'self mut T
}
impl<'self, A, T: Iterator<A>> Iterator<A> for ByRef<'self, T> {
#[inline]
fn next(&mut self) -> Option<A> { self.iter.next() }
// FIXME: #9629 we cannot implement &self methods like size_hint on ByRef
}
impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for ByRef<'self, T> {
#[inline]
fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
}
/// A trait for iterators over elements which can be added together
pub trait AdditiveIterator<A> {
/// Iterates over the entire iterator, summing up all the elements
@ -2500,6 +2535,15 @@ mod tests {
assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0);
}
#[test]
fn test_by_ref() {
let mut xs = range(0, 10);
// sum the first five values
let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
assert_eq!(partial_sum, 10);
assert_eq!(xs.next(), Some(5));
}
#[test]
fn test_invert() {
let xs = [2, 4, 6, 8, 10, 12, 14, 16];