extend the iterator tutorial
documents conversion, size hints and double-ended iterators and adds more of the traits to the prelude
This commit is contained in:
parent
07183ea6e7
commit
2b96408600
5 changed files with 115 additions and 15 deletions
|
@ -205,3 +205,104 @@ println(fmt!("last: %?", it.next()));
|
|||
// the iterator is now fully consumed
|
||||
assert!(it.next().is_none());
|
||||
~~~
|
||||
|
||||
## Conversion
|
||||
|
||||
Iterators offer generic conversion to containers with the `collect` adaptor:
|
||||
|
||||
~~~
|
||||
let xs = [0, 1, 1, 2, 3, 5, 8];
|
||||
let ys = xs.rev_iter().skip(1).transform(|&x| x * 2).collect::<~[int]>();
|
||||
assert_eq!(ys, ~[10, 6, 4, 2, 2, 0]);
|
||||
~~~
|
||||
|
||||
The method requires a type hint for the container type, if the surrounding code
|
||||
does not provide sufficient information.
|
||||
|
||||
Containers can provide conversion from iterators through `collect` by
|
||||
implementing the `FromIterator` trait. For example, the implementation for
|
||||
vectors is as follows:
|
||||
|
||||
~~~
|
||||
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
|
||||
pub fn from_iterator(iterator: &mut T) -> ~[A] {
|
||||
let (lower, _) = iterator.size_hint();
|
||||
let mut xs = with_capacity(lower);
|
||||
for iterator.advance |x| {
|
||||
xs.push(x);
|
||||
}
|
||||
xs
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
### Size hints
|
||||
|
||||
The `Iterator` trait provides a `size_hint` default method, returning a lower
|
||||
bound and optionally on upper bound on the length of the iterator:
|
||||
|
||||
~~~
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { (0, None) }
|
||||
~~~
|
||||
|
||||
The vector implementation of `FromIterator` from above uses the lower bound
|
||||
to pre-allocate enough space to hold the minimum number of elements the
|
||||
iterator will yield.
|
||||
|
||||
The default implementation is always correct, but it should be overridden if
|
||||
the iterator can provide better information.
|
||||
|
||||
The `ZeroStream` from earlier can provide an exact lower and upper bound:
|
||||
|
||||
~~~
|
||||
/// A stream of N zeroes
|
||||
struct ZeroStream {
|
||||
priv remaining: uint
|
||||
}
|
||||
|
||||
impl ZeroStream {
|
||||
fn new(n: uint) -> ZeroStream {
|
||||
ZeroStream { remaining: n }
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (uint, Option<uint>) {
|
||||
(self.remaining, Some(self.remaining))
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator<int> for ZeroStream {
|
||||
fn next(&mut self) -> Option<int> {
|
||||
if self.remaining == 0 {
|
||||
None
|
||||
} else {
|
||||
self.remaining -= 1;
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
## Double-ended iterators
|
||||
|
||||
The `DoubleEndedIterator` trait represents an iterator able to yield elements
|
||||
from either end of a range. It inherits from the `Iterator` trait and extends
|
||||
it with the `next_back` function.
|
||||
|
||||
A `DoubleEndedIterator` can be flipped with the `invert` adaptor, returning
|
||||
another `DoubleEndedIterator` with `next` and `next_back` exchanged.
|
||||
|
||||
~~~
|
||||
let xs = [1, 2, 3, 4, 5, 6];
|
||||
let mut it = xs.iter();
|
||||
println(fmt!("%?", it.next())); // prints `Some(&1)`
|
||||
println(fmt!("%?", it.next())); // prints `Some(&2)`
|
||||
println(fmt!("%?", it.next_back())); // prints `Some(&6)`
|
||||
|
||||
// prints `5`, `4` and `3`
|
||||
for it.invert().advance |&x| {
|
||||
println(fmt!("%?", x))
|
||||
}
|
||||
~~~
|
||||
|
||||
The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted
|
||||
version of the standard immutable and mutable vector iterators.
|
||||
|
|
|
@ -104,7 +104,7 @@ impl SmallBitv {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn invert(&mut self) { self.bits = !self.bits; }
|
||||
pub fn negate(&mut self) { self.bits = !self.bits; }
|
||||
}
|
||||
|
||||
struct BigBitv {
|
||||
|
@ -160,7 +160,7 @@ impl BigBitv {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn invert(&mut self) { for self.each_storage |w| { *w = !*w } }
|
||||
pub fn negate(&mut self) { for self.each_storage |w| { *w = !*w } }
|
||||
|
||||
#[inline]
|
||||
pub fn union(&mut self, b: &BigBitv, nbits: uint) -> bool {
|
||||
|
@ -366,9 +366,9 @@ impl Bitv {
|
|||
|
||||
/// Invert all bits
|
||||
#[inline]
|
||||
pub fn invert(&mut self) {
|
||||
pub fn negate(&mut self) {
|
||||
match self.rep {
|
||||
Small(ref mut b) => b.invert(),
|
||||
Small(ref mut b) => b.negate(),
|
||||
Big(ref mut s) => for s.each_storage() |w| { *w = !*w } }
|
||||
}
|
||||
|
||||
|
|
|
@ -47,8 +47,9 @@ pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Great
|
|||
pub use char::Char;
|
||||
pub use container::{Container, Mutable, Map, Set};
|
||||
pub use hash::Hash;
|
||||
pub use iter::{Times};
|
||||
pub use iterator::{Iterator, IteratorUtil, OrdIterator};
|
||||
pub use iter::Times;
|
||||
pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil};
|
||||
pub use iterator::OrdIterator;
|
||||
pub use num::{Num, NumCast};
|
||||
pub use num::{Orderable, Signed, Unsigned, Round};
|
||||
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
|
||||
|
|
|
@ -760,6 +760,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
|
|||
lifetime: cast::transmute(p)}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rev_iter(self) -> VecRevIterator<'self, T> {
|
||||
self.iter().invert()
|
||||
|
@ -2211,7 +2212,6 @@ impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use option::{None, Option, Some};
|
||||
|
|
|
@ -11,19 +11,17 @@
|
|||
use std::vec;
|
||||
|
||||
trait sum {
|
||||
fn sum(self) -> int;
|
||||
fn sum_(self) -> int;
|
||||
}
|
||||
|
||||
// Note: impl on a slice
|
||||
impl<'self> sum for &'self [int] {
|
||||
fn sum(self) -> int {
|
||||
let mut sum = 0;
|
||||
for self.iter().advance |e| { sum += *e; }
|
||||
return sum;
|
||||
fn sum_(self) -> int {
|
||||
self.iter().fold(0, |a, &b| a + b)
|
||||
}
|
||||
}
|
||||
|
||||
fn call_sum(x: &[int]) -> int { x.sum() }
|
||||
fn call_sum(x: &[int]) -> int { x.sum_() }
|
||||
|
||||
pub fn main() {
|
||||
let x = ~[1, 2, 3];
|
||||
|
@ -32,12 +30,12 @@ pub fn main() {
|
|||
assert_eq!(y, 6);
|
||||
|
||||
let mut x = ~[1, 2, 3];
|
||||
let y = x.sum();
|
||||
let y = x.sum_();
|
||||
debug!("y==%d", y);
|
||||
assert_eq!(y, 6);
|
||||
|
||||
let x = ~[1, 2, 3];
|
||||
let y = x.sum();
|
||||
let y = x.sum_();
|
||||
debug!("y==%d", y);
|
||||
assert_eq!(y, 6);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue