Skip to content

Commit 63e097d

Browse files
committed
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.
2 parents 9d6c251 + 8163cb5 commit 63e097d

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/libstd/iter.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,25 @@ pub trait Iterator<A> {
405405
Inspect{iter: self, f: f}
406406
}
407407

408+
/// Creates a wrapper around a mutable reference to the iterator.
409+
///
410+
/// This is useful to allow applying iterator adaptors while still
411+
/// retaining ownership of the original iterator value.
412+
///
413+
/// # Example
414+
///
415+
/// ```rust
416+
/// let mut xs = range(0, 10);
417+
/// // sum the first five values
418+
/// let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
419+
/// assert!(partial_sum == 10);
420+
/// // xs.next() is now `5`
421+
/// assert!(xs.next() == Some(5));
422+
/// ```
423+
fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> {
424+
ByRef{iter: self}
425+
}
426+
408427
/// An adaptation of an external iterator to the for-loop protocol of rust.
409428
///
410429
/// # Example
@@ -771,6 +790,22 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
771790
}
772791
}
773792

793+
/// A mutable reference to an iterator
794+
pub struct ByRef<'self, T> {
795+
priv iter: &'self mut T
796+
}
797+
798+
impl<'self, A, T: Iterator<A>> Iterator<A> for ByRef<'self, T> {
799+
#[inline]
800+
fn next(&mut self) -> Option<A> { self.iter.next() }
801+
// FIXME: #9629 we cannot implement &self methods like size_hint on ByRef
802+
}
803+
804+
impl<'self, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for ByRef<'self, T> {
805+
#[inline]
806+
fn next_back(&mut self) -> Option<A> { self.iter.next_back() }
807+
}
808+
774809
/// A trait for iterators over elements which can be added together
775810
pub trait AdditiveIterator<A> {
776811
/// Iterates over the entire iterator, summing up all the elements
@@ -2500,6 +2535,15 @@ mod tests {
25002535
assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0);
25012536
}
25022537

2538+
#[test]
2539+
fn test_by_ref() {
2540+
let mut xs = range(0, 10);
2541+
// sum the first five values
2542+
let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
2543+
assert_eq!(partial_sum, 10);
2544+
assert_eq!(xs.next(), Some(5));
2545+
}
2546+
25032547
#[test]
25042548
fn test_invert() {
25052549
let xs = [2, 4, 6, 8, 10, 12, 14, 16];

0 commit comments

Comments
 (0)