From 2b96408600c33b81c3c41f661764aa8d80cf3c9d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 11 Jul 2013 21:10:59 -0400 Subject: [PATCH] extend the iterator tutorial documents conversion, size hints and double-ended iterators and adds more of the traits to the prelude --- doc/tutorial-container.md | 101 ++++++++++++++++++++ src/libextra/bitv.rs | 8 +- src/libstd/prelude.rs | 5 +- src/libstd/vec.rs | 2 +- src/test/run-pass/rcvr-borrowed-to-slice.rs | 14 ++- 5 files changed, 115 insertions(+), 15 deletions(-) diff --git a/doc/tutorial-container.md b/doc/tutorial-container.md index 5ed61d693014..2146b76a4afb 100644 --- a/doc/tutorial-container.md +++ b/doc/tutorial-container.md @@ -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> FromIterator 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) { (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) { + (self.remaining, Some(self.remaining)) + } +} + +impl Iterator for ZeroStream { + fn next(&mut self) -> Option { + 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. diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index dc65ef36b67e..f1637ae96a20 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -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 } } } diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index db534cca971a..ea49144b7716 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -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}; diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 89c4b39c4293..4ab93da8c098 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -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> FromIterator for ~[A] { } } - #[cfg(test)] mod tests { use option::{None, Option, Some}; diff --git a/src/test/run-pass/rcvr-borrowed-to-slice.rs b/src/test/run-pass/rcvr-borrowed-to-slice.rs index b62475ded54f..3df60762dea0 100644 --- a/src/test/run-pass/rcvr-borrowed-to-slice.rs +++ b/src/test/run-pass/rcvr-borrowed-to-slice.rs @@ -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); }