Skip to content

Commit fb0b388

Browse files
committed
Make the iterator protocol more explicit
Document the fact that the iterator protocol only defines behavior up until the first None is returned. After this point, iterators are free to behave how they wish. Add a new iterator adaptor Fuse<T> that modifies iterators to return None forever if they returned None once.
1 parent 7c6c751 commit fb0b388

File tree

2 files changed

+145
-2
lines changed

2 files changed

+145
-2
lines changed

doc/tutorial-container.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,18 @@ impl Iterator<int> for ZeroStream {
105105
}
106106
~~~
107107
108+
In general, you cannot rely on the behavior of the `next()` method after it has
109+
returned `None`. Some iterators may return `None` forever. Others may behave
110+
differently.
111+
108112
## Container iterators
109113
110114
Containers implement iteration over the contained elements by returning an
111115
iterator object. For example, vector slices several iterators available:
112116
113117
* `iter()` and `rev_iter()`, for immutable references to the elements
114118
* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
115-
* `move_iter()` and `move_rev_iter`, to move the elements out by-value
119+
* `move_iter()` and `move_rev_iter()`, to move the elements out by-value
116120
117121
A typical mutable container will implement at least `iter()`, `mut_iter()` and
118122
`move_iter()` along with the reverse variants if it maintains an order.
@@ -149,7 +153,7 @@ let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
149153
assert_eq!(result, -41);
150154
~~~
151155
152-
Some adaptors return an adaptor object implementing the `Iterator` trait itself:
156+
Most adaptors return an adaptor object implementing the `Iterator` trait itself:
153157
154158
~~~
155159
let xs = [1, 9, 2, 3, 14, 12];
@@ -158,6 +162,35 @@ let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
158162
assert_eq!(sum, 57);
159163
~~~
160164
165+
Some iterator adaptors may return `None` before exhausting the underlying
166+
iterator. Additionally, if these iterator adaptors are called again after
167+
returning `None`, they may call their underlying iterator again even if the
168+
adaptor will continue to return `None` forever. This may not be desired if the
169+
underlying iterator has side-effects.
170+
171+
In order to provide a guarantee about behavior once `None` has been returned, an
172+
iterator adaptor named `fuse()` is provided. This returns an iterator that will
173+
never call its underlying iterator again once `None` has been returned:
174+
175+
~~~
176+
let xs = [1,2,3,4,5];
177+
let mut calls = 0;
178+
let it = xs.iter().scan((), |_, x| {
179+
calls += 1;
180+
if *x < 3 { Some(x) } else { None }});
181+
// the iterator will only yield 1 and 2 before returning None
182+
// If we were to call it 5 times, calls would end up as 5, despite only 2 values
183+
// being yielded (and therefore 3 unique calls being made). The fuse() adaptor
184+
// can fix this.
185+
let mut it = it.fuse();
186+
it.next();
187+
it.next();
188+
it.next();
189+
it.next();
190+
it.next();
191+
assert_eq!(calls, 3);
192+
~~~
193+
161194
## For loops
162195
163196
The function `range` (or `range_inclusive`) allows to simply iterate through a given range:

src/libstd/iterator.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ pub trait Extendable<A>: FromIterator<A> {
4141
/// An interface for dealing with "external iterators". These types of iterators
4242
/// can be resumed at any time as all state is stored internally as opposed to
4343
/// being located on the call stack.
44+
///
45+
/// The Iterator protocol states that an iterator yields a (potentially-empty,
46+
/// potentially-infinite) sequence of values, and returns `None` to signal that
47+
/// it's finished. The Iterator protocol does not define behavior after `None`
48+
/// is returned. A concrete Iterator implementation may choose to behave however
49+
/// it wishes, either by returning `None` infinitely, or by doing something
50+
/// else.
4451
pub trait Iterator<A> {
4552
/// Advance the iterator and return the next value. Return `None` when the end is reached.
4653
fn next(&mut self) -> Option<A>;
@@ -300,6 +307,36 @@ pub trait Iterator<A> {
300307
FlatMap{iter: self, f: f, frontiter: None, backiter: None }
301308
}
302309

310+
/// Creates an iterator that yields `None` forever after the underlying
311+
/// iterator yields `None`. Random-access iterator behavior is not
312+
/// affected, only single and double-ended iterator behavior.
313+
///
314+
/// # Example
315+
///
316+
/// ~~~ {.rust}
317+
/// fn process<U: Iterator<int>>(it: U) -> int {
318+
/// let mut it = it.fuse();
319+
/// let mut sum = 0;
320+
/// for x in it {
321+
/// if x > 5 {
322+
/// break;
323+
/// }
324+
/// sum += x;
325+
/// }
326+
/// // did we exhaust the iterator?
327+
/// if it.next().is_none() {
328+
/// sum += 1000;
329+
/// }
330+
/// sum
331+
/// }
332+
/// let x = ~[1,2,3,7,8,9];
333+
/// assert_eq!(process(x.move_iter()), 1006);
334+
/// ~~~
335+
#[inline]
336+
fn fuse(self) -> Fuse<Self> {
337+
Fuse{iter: self, done: false}
338+
}
339+
303340
/// Creates an iterator that calls a function with a reference to each
304341
/// element before yielding it. This is often useful for debugging an
305342
/// iterator pipeline.
@@ -1421,6 +1458,79 @@ impl<'self,
14211458
}
14221459
}
14231460

1461+
/// An iterator that yields `None` forever after the underlying iterator
1462+
/// yields `None` once.
1463+
#[deriving(Clone, DeepClone)]
1464+
pub struct Fuse<T> {
1465+
priv iter: T,
1466+
priv done: bool
1467+
}
1468+
1469+
impl<A, T: Iterator<A>> Iterator<A> for Fuse<T> {
1470+
#[inline]
1471+
fn next(&mut self) -> Option<A> {
1472+
if self.done {
1473+
None
1474+
} else {
1475+
match self.iter.next() {
1476+
None => {
1477+
self.done = true;
1478+
None
1479+
}
1480+
x => x
1481+
}
1482+
}
1483+
}
1484+
1485+
#[inline]
1486+
fn size_hint(&self) -> (uint, Option<uint>) {
1487+
if self.done {
1488+
(0, Some(0))
1489+
} else {
1490+
self.iter.size_hint()
1491+
}
1492+
}
1493+
}
1494+
1495+
impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Fuse<T> {
1496+
#[inline]
1497+
fn next_back(&mut self) -> Option<A> {
1498+
if self.done {
1499+
None
1500+
} else {
1501+
match self.iter.next_back() {
1502+
None => {
1503+
self.done = true;
1504+
None
1505+
}
1506+
x => x
1507+
}
1508+
}
1509+
}
1510+
}
1511+
1512+
// Allow RandomAccessIterators to be fused without affecting random-access behavior
1513+
impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Fuse<T> {
1514+
#[inline]
1515+
fn indexable(&self) -> uint {
1516+
self.iter.indexable()
1517+
}
1518+
1519+
#[inline]
1520+
fn idx(&self, index: uint) -> Option<A> {
1521+
self.iter.idx(index)
1522+
}
1523+
}
1524+
1525+
impl<T> Fuse<T> {
1526+
/// Resets the fuse such that the next call to .next() or .next_back() will
1527+
/// call the underlying iterator again even if it prevously returned None.
1528+
#[inline]
1529+
fn reset_fuse(&mut self) {
1530+
self.done = false
1531+
}
1532+
}
1533+
14241534
/// An iterator that calls a function with a reference to each
14251535
/// element before yielding it.
14261536
pub struct Inspect<'self, A, T> {

0 commit comments

Comments
 (0)