From 1fbf8bb6640e6ddea034eac32f558b428da52477 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 8 Oct 2015 15:34:14 -0400 Subject: [PATCH] Write better module-level docs for std::iter This replaces what was there with a comprehensive overview. --- src/libcore/iter.rs | 300 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 271 insertions(+), 29 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 00c7773fd8b..94565389c8d 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -8,51 +8,293 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Composable external iterators +//! Composable external iteration //! -//! # The `Iterator` trait +//! If you've found yourself with a collection of some kind, and needed to +//! perform an operation on the elements of said collection, you'll quickly run +//! into 'iterators'. Iterators are heavily used in idiomatic Rust code, so +//! it's worth becoming familiar with them. //! -//! This module defines Rust's core iteration trait. The `Iterator` trait has -//! one unimplemented method, `next`. All other methods are derived through -//! default methods to perform operations such as `zip`, `chain`, `enumerate`, -//! and `fold`. +//! Before explaining more, let's talk about how this module is structured: //! -//! The goal of this module is to unify iteration across all containers in Rust. -//! An iterator can be considered as a state machine which is used to track -//! which element will be yielded next. +//! # Organization //! -//! There are various extensions also defined in this module to assist with -//! various types of iteration, such as the `DoubleEndedIterator` for iterating -//! in reverse, the `FromIterator` trait for creating a container from an -//! iterator, and much more. +//! This module is largely organized by type: //! -//! # Rust's `for` loop +//! * [Traits] are the core portion: these traits define what kind of iterators +//! exist and what you can do with them. The methods of these traits are worth +//! putting some extra study time into. +//! * [Functions] provide some helpful ways to create some basic iterators. +//! * [Structs] are often the return types of the various methods on this +//! module's traits. You'll usually want to look at the method that creates +//! the `struct`, rather than the `struct` itself. For more detail about why, +//! see '[Implementing Iterator](#implementing-iterator)'. //! -//! The special syntax used by rust's `for` loop is based around the -//! `IntoIterator` trait defined in this module. `for` loops can be viewed as a -//! syntactical expansion into a `loop`, for example, the `for` loop in this -//! example is essentially translated to the `loop` below. +//! [Traits]: #traits +//! [Functions]: #functions +//! [Structs]: #structs +//! +//! That's it! Let's dig into iterators. +//! +//! # Iterator +//! +//! The heart and soul of this module is the [`Iterator`] trait. The core of +//! [`Iterator`] looks like this: //! //! ``` -//! let values = vec![1, 2, 3]; +//! trait Iterator { +//! type Item; +//! fn next(&mut self) -> Option; +//! } +//! ``` +//! +//! An iterator has a method, [`next()`], which when called, returns an +//! [`Option`]``. [`next()`] will return `Some(Item)` as long as there +//! are elements, and once they've all been exhausted, will return `None` to +//! indicate that iteration is finished. Individual iterators may choose to +//! resume iteration, and so calling [`next()`] again may or may not eventually +//! start returning `Some(Item)` again at some point. +//! +//! [`Iterator`]'s full definition includes a number of other methods as well, +//! but they are default methods, built on top of [`next()`], and so you get +//! them for free. +//! +//! Iterators are also composable, and it's common to chain them together to do +//! more complex forms of processing. See the [Adapters](#adapters) section +//! below for more details. +//! +//! [`Iterator`]: trait.Iterator.html +//! [`next()`]: trait.Iterator.html#tymethod.next +//! [`Option`]: ../option/enum.Option.html +//! +//! # The three forms of iteration +//! +//! There are three common methods which can create iterators from a collection: +//! +//! * `iter()`, which iterates over `&T`. +//! * `iter_mut()`, which iterates over `&mut T`. +//! * `into_iter()`, which iterates over `T`. +//! +//! Various things in the standard library may implement one or more of the +//! three, where appropriate. +//! +//! # Implementing Iterator +//! +//! Creating an iterator of your own involves two steps: creating a `struct` to +//! hold the iterator's state, and then `impl`ementing [`Iterator`] for that +//! `struct`. This is why there are so many `struct`s in this module: there is +//! one for each iterator and iterator adapter. +//! +//! Let's make an iterator named `Counter` which counts from `1` to `5`: +//! +//! ``` +//! // First, the struct: +//! +//! /// An iterator which counts from one to five +//! struct Counter { +//! count: i32, +//! } +//! +//! // we want our count to start at one, so let's add a new() method to help. +//! // This isn't strictly necessary, but is convenient. Note that we start +//! // `count` at zero, we'll see why in `next()`'s implementation below. +//! impl Counter { +//! fn new() -> Counter { +//! Counter { count: 0 } +//! } +//! } +//! +//! // Then, we implement `Iterator` for our `Counter`: +//! +//! impl Iterator for Counter { +//! // we will be counting with i32 +//! type Item = i32; +//! +//! // next() is the only required method +//! fn next(&mut self) -> Option { +//! // increment our count. This is why we started at zero. +//! self.count += 1; +//! +//! // check to see if we've finished counting or not. +//! if self.count < 6 { +//! Some(self.count) +//! } else { +//! None +//! } +//! } +//! } +//! +//! // And now we can use it! +//! +//! let mut counter = Counter::new(); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! +//! let x = counter.next().unwrap(); +//! println!("{}", x); +//! ``` +//! +//! This will print `1` through `5`, each on their own line. +//! +//! Calling `next()` this way gets repetitive. Rust has a construct which can +//! call `next()` on your iterator, until it reaches `None`. Let's go over that +//! next. +//! +//! # for Loops and IntoIterator +//! +//! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic +//! example of `for`: +//! +//! ``` +//! let values = vec![1, 2, 3, 4, 5]; //! //! for x in values { //! println!("{}", x); //! } +//! ``` //! -//! // Rough translation of the iteration without a `for` iterator. -//! # let values = vec![1, 2, 3]; -//! let mut it = values.into_iter(); -//! loop { -//! match it.next() { -//! Some(x) => println!("{}", x), -//! None => break, -//! } +//! This will print the numbers one through five, each on their own line. But +//! you'll notice something here: we never called anything on our vector to +//! produce an iterator. What gives? +//! +//! There's a trait in the standard library for converting something into an +//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter()`], +//! which converts the thing implementing [`IntoIterator`] into an iterator. +//! Let's take a look at that `for` loop again, and what the compiler converts +//! it into: +//! +//! [`IntoIterator`]: trait.IntoIterator.html +//! [`into_iter()`]: trait.IntoIterator.html#tymethod.into_iter +//! +//! ``` +//! let values = vec![1, 2, 3, 4, 5]; +//! +//! for x in values { +//! println!("{}", x); //! } //! ``` //! -//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be -//! applied to any iterator over any type. +//! Rust de-sugars this into: +//! +//! ``` +//! let values = vec![1, 2, 3, 4, 5]; +//! { +//! let result = match values.into_iter() { +//! mut iter => loop { +//! match iter.next() { +//! Some(x) => { println!("{}", x); }, +//! None => break, +//! } +//! }, +//! }; +//! result +//! } +//! ``` +//! +//! First, we call `into_iter()` on the value. Then, we match on the iterator +//! that returns, calling [`next()`] over and over until we see a `None`. At +//! that point, we `break` out of the loop, and we're done iterating. +//! +//! There's one more subtle bit here: the standard library contains an +//! interesting implementation of [`IntoIterator`]: +//! +//! ```ignore +//! impl IntoIterator for I where I: Iterator +//! ``` +//! +//! In other words, all [`Iterator`]s implement [`IntoIterator`], by just +//! returning themselves. This means two things: +//! +//! 1. If you're writing an [`Iterator`], you can use it with a `for` loop. +//! 2. If you're creating a collection, implementing [`IntoIterator`] for it +//! will allow your collection to be used with the `for` loop. +//! +//! # Adapters +//! +//! Functions which take an [`Iterator`] and return another [`Iterator`] are +//! often called 'iterator adapters', as they're a form of the 'adapter +//! pattern'. +//! +//! Common iterator adapters include [`map()`], [`take()`], and [`collect()`]. +//! For more, see their documentation. +//! +//! [`map()`]: trait.Iterator.html#method.map +//! [`take()`]: trait.Iterator.html#method.take +//! [`collect()`]: trait.Iterator.html#method.collect +//! +//! # Laziness +//! +//! Iterators (and iterator [adapters](#adapters)) are *lazy*. This means that +//! just creating an iterator doesn't _do_ a whole lot. Nothing really happens +//! until you call [`next()`]. This is sometimes a source of confusion when +//! creating an iterator solely for its side effects. For example, the [`map()`] +//! method calls a closure on each element it iterates over: +//! +//! ``` +//! let v = vec![1, 2, 3, 4, 5]; +//! v.iter().map(|x| println!("{}", x)); +//! ``` +//! +//! This will not print any values, as we only created an iterator, rather than +//! using it. The compiler will warn us about this kind of behavior: +//! +//! ```text +//! warning: unused result which must be used: iterator adaptors are lazy and +//! do nothing unless consumed +//! ``` +//! +//! The idiomatic way to write a [`map()`] for its side effects is to use a +//! `for` loop instead: +//! +//! ``` +//! let v = vec![1, 2, 3, 4, 5]; +//! +//! for x in &v { +//! println!("{}", x); +//! } +//! ``` +//! +//! [`map()`]: trait.Iterator.html#method.map +//! +//! The two most common ways to evaluate an iterator are to use a `for` loop +//! like this, or using the [`collect()`] adapter to produce a new collection. +//! +//! [`collect()`]: trait.Iterator.html#method.collect +//! +//! # Infinity +//! +//! Iterators do not have to be finite. As an example, an open-ended range is +//! an infinite iterator: +//! +//! ``` +//! let numbers = 0..; +//! ``` +//! +//! It is common to use the [`take()`] iterator adapter to turn an infinite +//! iterator into a finite one: +//! +//! ``` +//! let numbers = 0..; +//! let five_numbers = numbers.take(5); +//! +//! for number in five_numbers { +//! println!("{}", number); +//! } +//! ``` +//! +//! This will print the numbers `0` through `4`, each on their own line. +//! +//! [`take()`]: trait.Iterator.html#method.take #![stable(feature = "rust1", since = "1.0.0")]