mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-21 11:23:03 +00:00
Remove container guide.
This isn't really what guides are for, this information belongs in the module-level docs. Fixes #9314.
This commit is contained in:
parent
84030fd05a
commit
1b818020a0
@ -1,414 +1,6 @@
|
|||||||
% The Rust Containers and Iterators Guide
|
% The Rust Containers and Iterators Guide
|
||||||
|
|
||||||
# Containers
|
This guide has been removed, with no direct replacement.
|
||||||
|
|
||||||
The container traits are defined in the `std::container` module.
|
You may enjoy reading the [iterator](std/iter/index.html) and
|
||||||
|
[collections](std/collections/index.html) documentation.
|
||||||
## Unique vectors
|
|
||||||
|
|
||||||
Vectors have `O(1)` indexing, push (to the end) and pop (from the end). Vectors
|
|
||||||
are the most common container in Rust, and are flexible enough to fit many use
|
|
||||||
cases.
|
|
||||||
|
|
||||||
Vectors can also be sorted and used as efficient lookup tables with the
|
|
||||||
`bsearch()` method, if all the elements are inserted at one time and
|
|
||||||
deletions are unnecessary.
|
|
||||||
|
|
||||||
## Maps and sets
|
|
||||||
|
|
||||||
Maps are collections of unique keys with corresponding values, and sets are
|
|
||||||
just unique keys without a corresponding value. The `Map` and `Set` traits in
|
|
||||||
`std::container` define the basic interface.
|
|
||||||
|
|
||||||
The standard library provides three owned map/set types:
|
|
||||||
|
|
||||||
* `collections::HashMap` and `collections::HashSet`, requiring the keys to
|
|
||||||
implement `Eq` and `Hash`
|
|
||||||
* `collections::TrieMap` and `collections::TrieSet`, requiring the keys to be `uint`
|
|
||||||
* `collections::TreeMap` and `collections::TreeSet`, requiring the keys
|
|
||||||
to implement `Ord`
|
|
||||||
|
|
||||||
These maps do not use managed pointers so they can be sent between tasks as
|
|
||||||
long as the key and value types are sendable. Neither the key or value type has
|
|
||||||
to be copyable.
|
|
||||||
|
|
||||||
The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary
|
|
||||||
order.
|
|
||||||
|
|
||||||
Each `HashMap` instance has a random 128-bit key to use with a keyed hash,
|
|
||||||
making the order of a set of keys in a given hash table randomized. Rust
|
|
||||||
provides a [SipHash](https://131002.net/siphash/) implementation for any type
|
|
||||||
implementing the `Hash` trait.
|
|
||||||
|
|
||||||
## Double-ended queues
|
|
||||||
|
|
||||||
The `collections::ringbuf` module implements a double-ended queue with `O(1)`
|
|
||||||
amortized inserts and removals from both ends of the container. It also has
|
|
||||||
`O(1)` indexing like a vector. The contained elements are not required to be
|
|
||||||
copyable, and the queue will be sendable if the contained type is sendable.
|
|
||||||
Its interface `Deque` is defined in `collections`.
|
|
||||||
|
|
||||||
The `extra::dlist` module implements a double-ended linked list, also
|
|
||||||
implementing the `Deque` trait, with `O(1)` removals and inserts at either end,
|
|
||||||
and `O(1)` concatenation.
|
|
||||||
|
|
||||||
## Priority queues
|
|
||||||
|
|
||||||
The `collections::priority_queue` module implements a queue ordered by a key. The
|
|
||||||
contained elements are not required to be copyable, and the queue will be
|
|
||||||
sendable if the contained type is sendable.
|
|
||||||
|
|
||||||
Insertions have `O(log n)` time complexity and checking or popping the largest
|
|
||||||
element is `O(1)`. Converting a vector to a priority queue can be done
|
|
||||||
in-place, and has `O(n)` complexity. A priority queue can also be converted to
|
|
||||||
a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place
|
|
||||||
heapsort.
|
|
||||||
|
|
||||||
# Iterators
|
|
||||||
|
|
||||||
## Iteration protocol
|
|
||||||
|
|
||||||
The iteration protocol is defined by the `Iterator` trait in the
|
|
||||||
`std::iter` module. The minimal implementation of the trait is a `next`
|
|
||||||
method, yielding the next element from an iterator object:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
/// An infinite stream of zeroes
|
|
||||||
struct ZeroStream;
|
|
||||||
|
|
||||||
impl Iterator<int> for ZeroStream {
|
|
||||||
fn next(&mut self) -> Option<int> {
|
|
||||||
Some(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Reaching the end of the iterator is signalled by returning `None` instead of
|
|
||||||
`Some(item)`:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
# fn main() {}
|
|
||||||
/// A stream of N zeroes
|
|
||||||
struct ZeroStream {
|
|
||||||
remaining: uint
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ZeroStream {
|
|
||||||
fn new(n: uint) -> ZeroStream {
|
|
||||||
ZeroStream { remaining: n }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator<int> for ZeroStream {
|
|
||||||
fn next(&mut self) -> Option<int> {
|
|
||||||
if self.remaining == 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.remaining -= 1;
|
|
||||||
Some(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
In general, you cannot rely on the behavior of the `next()` method after it has
|
|
||||||
returned `None`. Some iterators may return `None` forever. Others may behave
|
|
||||||
differently.
|
|
||||||
|
|
||||||
## Container iterators
|
|
||||||
|
|
||||||
Containers implement iteration over the contained elements by returning an
|
|
||||||
iterator object. For example, for vector slices several iterators are available:
|
|
||||||
|
|
||||||
* `iter()` for immutable references to the elements
|
|
||||||
* `mut_iter()` for mutable references to the elements
|
|
||||||
* `move_iter()` to move the elements out by-value
|
|
||||||
|
|
||||||
A typical mutable container will implement at least `iter()`, `mut_iter()` and
|
|
||||||
`move_iter()`. If it maintains an order, the returned iterators will be
|
|
||||||
`DoubleEndedIterator`s, which are described below.
|
|
||||||
|
|
||||||
### Freezing
|
|
||||||
|
|
||||||
Unlike most other languages with external iterators, Rust has no *iterator
|
|
||||||
invalidation*. As long as an iterator is still in scope, the compiler will prevent
|
|
||||||
modification of the container through another handle.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let mut xs = [1i, 2, 3];
|
|
||||||
{
|
|
||||||
let _it = xs.iter();
|
|
||||||
|
|
||||||
// the vector is frozen for this scope, the compiler will statically
|
|
||||||
// prevent modification
|
|
||||||
}
|
|
||||||
// the vector becomes unfrozen again at the end of the scope
|
|
||||||
~~~
|
|
||||||
|
|
||||||
These semantics are due to most container iterators being implemented with `&`
|
|
||||||
and `&mut`.
|
|
||||||
|
|
||||||
## Iterator adaptors
|
|
||||||
|
|
||||||
The `Iterator` trait provides many common algorithms as default methods. For
|
|
||||||
example, the `fold` method will accumulate the items yielded by an `Iterator`
|
|
||||||
into a single value:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i, 9, 2, 3, 14, 12];
|
|
||||||
let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
|
|
||||||
assert_eq!(result, -41);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Most adaptors return an adaptor object implementing the `Iterator` trait itself:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i, 9, 2, 3, 14, 12];
|
|
||||||
let ys = [5i, 2, 1, 8];
|
|
||||||
let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
|
|
||||||
assert_eq!(sum, 57);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
Some iterator adaptors may return `None` before exhausting the underlying
|
|
||||||
iterator. Additionally, if these iterator adaptors are called again after
|
|
||||||
returning `None`, they may call their underlying iterator again even if the
|
|
||||||
adaptor will continue to return `None` forever. This may not be desired if the
|
|
||||||
underlying iterator has side-effects.
|
|
||||||
|
|
||||||
In order to provide a guarantee about behavior once `None` has been returned, an
|
|
||||||
iterator adaptor named `fuse()` is provided. This returns an iterator that will
|
|
||||||
never call its underlying iterator again once `None` has been returned:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i,2,3,4,5];
|
|
||||||
let mut calls = 0i;
|
|
||||||
|
|
||||||
{
|
|
||||||
let it = xs.iter().scan((), |_, x| {
|
|
||||||
calls += 1;
|
|
||||||
if *x < 3 { Some(x) } else { None }});
|
|
||||||
|
|
||||||
// the iterator will only yield 1 and 2 before returning None
|
|
||||||
// If we were to call it 5 times, calls would end up as 5, despite
|
|
||||||
// only 2 values being yielded (and therefore 3 unique calls being
|
|
||||||
// made). The fuse() adaptor can fix this.
|
|
||||||
|
|
||||||
let mut it = it.fuse();
|
|
||||||
it.next();
|
|
||||||
it.next();
|
|
||||||
it.next();
|
|
||||||
it.next();
|
|
||||||
it.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(calls, 3);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## For loops
|
|
||||||
|
|
||||||
The function `range` (or `range_inclusive`) allows to simply iterate through a given range:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
for i in range(0i, 5) {
|
|
||||||
print!("{} ", i) // prints "0 1 2 3 4"
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in std::iter::range_inclusive(0i, 5) { // needs explicit import
|
|
||||||
print!("{} ", i) // prints "0 1 2 3 4 5"
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
The `for` keyword can be used as sugar for iterating through any iterator:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [2u, 3, 5, 7, 11, 13, 17];
|
|
||||||
|
|
||||||
// print out all the elements in the vector
|
|
||||||
for x in xs.iter() {
|
|
||||||
println!("{}", *x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// print out all but the first 3 elements in the vector
|
|
||||||
for x in xs.iter().skip(3) {
|
|
||||||
println!("{}", *x)
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
For loops are *often* used with a temporary iterator object, as above. They can
|
|
||||||
also advance the state of an iterator in a mutable location:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i, 2, 3, 4, 5];
|
|
||||||
let ys = ["foo", "bar", "baz", "foobar"];
|
|
||||||
|
|
||||||
// create an iterator yielding tuples of elements from both vectors
|
|
||||||
let mut it = xs.iter().zip(ys.iter());
|
|
||||||
|
|
||||||
// print out the pairs of elements up to (&3, &"baz")
|
|
||||||
for (x, y) in it {
|
|
||||||
println!("{} {}", *x, *y);
|
|
||||||
|
|
||||||
if *x == 3 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// yield and print the last pair from the iterator
|
|
||||||
println!("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 = [0i, 1, 1, 2, 3, 5, 8];
|
|
||||||
let ys = xs.iter().rev().skip(1).map(|&x| x * 2).collect::<Vec<int>>();
|
|
||||||
assert_eq!(ys, vec![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:
|
|
||||||
|
|
||||||
~~~ {.ignore}
|
|
||||||
impl<T> FromIterator<T> for Vec<T> {
|
|
||||||
fn from_iter<I:Iterator<A>>(mut iterator: I) -> Vec<T> {
|
|
||||||
let (lower, _) = iterator.size_hint();
|
|
||||||
let mut vector = Vec::with_capacity(lower);
|
|
||||||
for element in iterator {
|
|
||||||
vector.push(element);
|
|
||||||
}
|
|
||||||
vector
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
### 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:
|
|
||||||
|
|
||||||
~~~ {.ignore}
|
|
||||||
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:
|
|
||||||
|
|
||||||
~~~
|
|
||||||
# fn main() {}
|
|
||||||
/// A stream of N zeroes
|
|
||||||
struct ZeroStream {
|
|
||||||
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 have its direction changed with the `rev` adaptor,
|
|
||||||
returning another `DoubleEndedIterator` with `next` and `next_back` exchanged.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i, 2, 3, 4, 5, 6];
|
|
||||||
let mut it = xs.iter();
|
|
||||||
println!("{}", it.next()); // prints `Some(1)`
|
|
||||||
println!("{}", it.next()); // prints `Some(2)`
|
|
||||||
println!("{}", it.next_back()); // prints `Some(6)`
|
|
||||||
|
|
||||||
// prints `5`, `4` and `3`
|
|
||||||
for &x in it.rev() {
|
|
||||||
println!("{}", x)
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
The `chain`, `map`, `filter`, `filter_map` and `inspect` adaptors are
|
|
||||||
`DoubleEndedIterator` implementations if the underlying iterators are.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i, 2, 3, 4];
|
|
||||||
let ys = [5i, 6, 7, 8];
|
|
||||||
let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2);
|
|
||||||
|
|
||||||
println!("{}", it.next()); // prints `Some(2)`
|
|
||||||
|
|
||||||
// prints `16`, `14`, `12`, `10`, `8`, `6`, `4`
|
|
||||||
for x in it.rev() {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
~~~
|
|
||||||
|
|
||||||
The `reverse_` method is also available for any double-ended iterator yielding
|
|
||||||
mutable references. It can be used to reverse a container in-place. Note that
|
|
||||||
the trailing underscore is a workaround for issue #5898 and will be removed.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let mut ys = [1i, 2, 3, 4, 5];
|
|
||||||
ys.mut_iter().reverse_();
|
|
||||||
assert!(ys == [5i, 4, 3, 2, 1]);
|
|
||||||
~~~
|
|
||||||
|
|
||||||
## Random-access iterators
|
|
||||||
|
|
||||||
The `RandomAccessIterator` trait represents an iterator offering random access
|
|
||||||
to the whole range. The `indexable` method retrieves the number of elements
|
|
||||||
accessible with the `idx` method.
|
|
||||||
|
|
||||||
The `chain` adaptor is an implementation of `RandomAccessIterator` if the
|
|
||||||
underlying iterators are.
|
|
||||||
|
|
||||||
~~~
|
|
||||||
let xs = [1i, 2, 3, 4, 5];
|
|
||||||
let ys = [7i, 9, 11];
|
|
||||||
let mut it = xs.iter().chain(ys.iter());
|
|
||||||
println!("{}", it.idx(0)); // prints `Some(1)`
|
|
||||||
println!("{}", it.idx(5)); // prints `Some(7)`
|
|
||||||
println!("{}", it.idx(7)); // prints `Some(11)`
|
|
||||||
println!("{}", it.idx(8)); // prints `None`
|
|
||||||
|
|
||||||
// yield two elements from the beginning, and one from the end
|
|
||||||
it.next();
|
|
||||||
it.next();
|
|
||||||
it.next_back();
|
|
||||||
|
|
||||||
println!("{}", it.idx(0)); // prints `Some(3)`
|
|
||||||
println!("{}", it.idx(4)); // prints `Some(9)`
|
|
||||||
println!("{}", it.idx(6)); // prints `None`
|
|
||||||
~~~
|
|
||||||
|
@ -57,7 +57,6 @@ a guide that can help you out:
|
|||||||
* [Strings](guide-strings.html)
|
* [Strings](guide-strings.html)
|
||||||
* [Pointers](guide-pointers.html)
|
* [Pointers](guide-pointers.html)
|
||||||
* [References and Lifetimes](guide-lifetimes.html)
|
* [References and Lifetimes](guide-lifetimes.html)
|
||||||
* [Containers and Iterators](guide-container.html)
|
|
||||||
* [Tasks and Communication](guide-tasks.html)
|
* [Tasks and Communication](guide-tasks.html)
|
||||||
* [Foreign Function Interface](guide-ffi.html)
|
* [Foreign Function Interface](guide-ffi.html)
|
||||||
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
|
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
|
||||||
|
@ -56,12 +56,6 @@ loop {
|
|||||||
|
|
||||||
This `for` loop syntax can be applied to any iterator over any type.
|
This `for` loop syntax can be applied to any iterator over any type.
|
||||||
|
|
||||||
## Iteration protocol and more
|
|
||||||
|
|
||||||
More detailed information about iterators can be found in the [container
|
|
||||||
guide](http://doc.rust-lang.org/guide-container.html) with
|
|
||||||
the rest of the rust manuals.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use clone::Clone;
|
use clone::Clone;
|
||||||
|
Loading…
Reference in New Issue
Block a user