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:
@@ -205,3 +205,104 @@ println(fmt!("last: %?", it.next()));
|
|||||||
// the iterator is now fully consumed
|
// the iterator is now fully consumed
|
||||||
assert!(it.next().is_none());
|
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]
|
#[inline]
|
||||||
pub fn invert(&mut self) { self.bits = !self.bits; }
|
pub fn negate(&mut self) { self.bits = !self.bits; }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BigBitv {
|
struct BigBitv {
|
||||||
@@ -160,7 +160,7 @@ impl BigBitv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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]
|
#[inline]
|
||||||
pub fn union(&mut self, b: &BigBitv, nbits: uint) -> bool {
|
pub fn union(&mut self, b: &BigBitv, nbits: uint) -> bool {
|
||||||
@@ -366,9 +366,9 @@ impl Bitv {
|
|||||||
|
|
||||||
/// Invert all bits
|
/// Invert all bits
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn invert(&mut self) {
|
pub fn negate(&mut self) {
|
||||||
match self.rep {
|
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 } }
|
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 char::Char;
|
||||||
pub use container::{Container, Mutable, Map, Set};
|
pub use container::{Container, Mutable, Map, Set};
|
||||||
pub use hash::Hash;
|
pub use hash::Hash;
|
||||||
pub use iter::{Times};
|
pub use iter::Times;
|
||||||
pub use iterator::{Iterator, IteratorUtil, OrdIterator};
|
pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil};
|
||||||
|
pub use iterator::OrdIterator;
|
||||||
pub use num::{Num, NumCast};
|
pub use num::{Num, NumCast};
|
||||||
pub use num::{Orderable, Signed, Unsigned, Round};
|
pub use num::{Orderable, Signed, Unsigned, Round};
|
||||||
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
|
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
|
||||||
|
|||||||
@@ -760,6 +760,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
|
|||||||
lifetime: cast::transmute(p)}
|
lifetime: cast::transmute(p)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rev_iter(self) -> VecRevIterator<'self, T> {
|
fn rev_iter(self) -> VecRevIterator<'self, T> {
|
||||||
self.iter().invert()
|
self.iter().invert()
|
||||||
@@ -2211,7 +2212,6 @@ impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use option::{None, Option, Some};
|
use option::{None, Option, Some};
|
||||||
|
|||||||
@@ -11,19 +11,17 @@
|
|||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
trait sum {
|
trait sum {
|
||||||
fn sum(self) -> int;
|
fn sum_(self) -> int;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: impl on a slice
|
// Note: impl on a slice
|
||||||
impl<'self> sum for &'self [int] {
|
impl<'self> sum for &'self [int] {
|
||||||
fn sum(self) -> int {
|
fn sum_(self) -> int {
|
||||||
let mut sum = 0;
|
self.iter().fold(0, |a, &b| a + b)
|
||||||
for self.iter().advance |e| { sum += *e; }
|
|
||||||
return sum;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_sum(x: &[int]) -> int { x.sum() }
|
fn call_sum(x: &[int]) -> int { x.sum_() }
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let x = ~[1, 2, 3];
|
let x = ~[1, 2, 3];
|
||||||
@@ -32,12 +30,12 @@ pub fn main() {
|
|||||||
assert_eq!(y, 6);
|
assert_eq!(y, 6);
|
||||||
|
|
||||||
let mut x = ~[1, 2, 3];
|
let mut x = ~[1, 2, 3];
|
||||||
let y = x.sum();
|
let y = x.sum_();
|
||||||
debug!("y==%d", y);
|
debug!("y==%d", y);
|
||||||
assert_eq!(y, 6);
|
assert_eq!(y, 6);
|
||||||
|
|
||||||
let x = ~[1, 2, 3];
|
let x = ~[1, 2, 3];
|
||||||
let y = x.sum();
|
let y = x.sum_();
|
||||||
debug!("y==%d", y);
|
debug!("y==%d", y);
|
||||||
assert_eq!(y, 6);
|
assert_eq!(y, 6);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user