about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2020-12-13 11:05:22 +0900
committerGitHub <noreply@github.com>2020-12-13 11:05:22 +0900
commit1698773263f89c9f3507eddef032f76ae065e0da (patch)
tree9dfc1446ddd9f3e757107a6aabb0ff985865270c
parentf61e5cab760e21d61d8ba3d58badb20c54ebb1c4 (diff)
parent6edc90a3e21a786bfe1e0a6bca28e8e687064554 (diff)
downloadrust-1698773263f89c9f3507eddef032f76ae065e0da.tar.gz
rust-1698773263f89c9f3507eddef032f76ae065e0da.zip
Rollup merge of #79360 - wchargin:wchargin-doc-iter-by-reference, r=m-ou-se
std::iter: document iteration over `&T` and `&mut T`

A colleague of mine is new to Rust, and mentioned that it was “slightly
confusing” to figure out what `&mut` does in iterating over `&mut foo`:

```rust
for value in &mut self.my_vec {
    // ...
}
```

My colleague had read the `std::iter` docs and not found the answer
there. There is a brief section at the top about “the three forms of
iteration”, which mentions `iter_mut`, but it doesn’t cover the purpose
of `&mut coll` for a collection `coll`. This patch adds an explanatory
section to the docs. I opted to create a new section so that it can
appear after the note that `impl<I: Iterator> IntoIterator for I`, and
it’s nice for the existing “three forms of iteration” to appear near the
top.

Test Plan:
Ran `./x.py doc library/core`, and the result looked good, including
links. Manually copy-pasted the two doctests into the playground and ran
them.

wchargin-branch: doc-iter-by-reference
-rw-r--r--library/core/src/iter/mod.rs45
1 files changed, 45 insertions, 0 deletions
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 072373c00f6..3e74637b49f 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -206,6 +206,51 @@
 //! 2. If you're creating a collection, implementing [`IntoIterator`] for it
 //!    will allow your collection to be used with the `for` loop.
 //!
+//! # Iterating by reference
+//!
+//! Since [`into_iter()`] takes `self` by value, using a `for` loop to iterate
+//! over a collection consumes that collection. Often, you may want to iterate
+//! over a collection without consuming it. Many collections offer methods that
+//! provide iterators over references, conventionally called `iter()` and
+//! `iter_mut()` respectively:
+//!
+//! ```
+//! let mut values = vec![41];
+//! for x in values.iter_mut() {
+//!     *x += 1;
+//! }
+//! for x in values.iter() {
+//!     assert_eq!(*x, 42);
+//! }
+//! assert_eq!(values.len(), 1); // `values` is still owned by this function.
+//! ```
+//!
+//! If a collection type `C` provides `iter()`, it usually also implements
+//! `IntoIterator` for `&C`, with an implementation that just calls `iter()`.
+//! Likewise, a collection `C` that provides `iter_mut()` generally implements
+//! `IntoIterator` for `&mut C` by delegating to `iter_mut()`. This enables a
+//! convenient shorthand:
+//!
+//! ```
+//! let mut values = vec![41];
+//! for x in &mut values { // same as `values.iter_mut()`
+//!     *x += 1;
+//! }
+//! for x in &values { // same as `values.iter()`
+//!     assert_eq!(*x, 42);
+//! }
+//! assert_eq!(values.len(), 1);
+//! ```
+//!
+//! While many collections offer `iter()`, not all offer `iter_mut()`. For
+//! example, mutating the keys of a [`HashSet<T>`] or [`HashMap<K, V>`] could
+//! put the collection into an inconsistent state if the key hashes change, so
+//! these collections only offer `iter()`.
+//!
+//! [`into_iter()`]: IntoIterator::into_iter
+//! [`HashSet<T>`]: ../../std/collections/struct.HashSet.html
+//! [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
+//!
 //! # Adapters
 //!
 //! Functions which take an [`Iterator`] and return another [`Iterator`] are