From 7deb057d550b120aebe6576f860362cec38e3cf3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 26 Jan 2016 13:03:31 -0500 Subject: [PATCH] Discuss pitfalls of stateful closures with Map Fixes #30632 --- src/libcore/iter.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3f1c0f6a5492a..b9ca99628e5d0 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -3276,6 +3276,49 @@ impl DoubleEndedIterator for Zip where /// /// [`map()`]: trait.Iterator.html#method.map /// [`Iterator`]: trait.Iterator.html +/// +/// # Notes about side effects +/// +/// The [`map()`] iterator implements [`DoubleEndedIterator`], meaning that +/// you can also [`map()`] backwards: +/// +/// ```rust +/// let v: Vec = vec![1, 2, 3].into_iter().rev().map(|x| x + 1).collect(); +/// +/// assert_eq!(v, [4, 3, 2]); +/// ``` +/// +/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html +/// +/// But if your closure has state, iterating backwards may act in a way you do +/// not expect. Let's go through an example. First, in the forward direction: +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) { +/// println!("{:?}", pair); +/// } +/// ``` +/// +/// This will print "('a', 1), ('b', 2), ('c', 3)". +/// +/// Now consider this twist where we add a call to `rev`. This version will +/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, +/// but the values of the counter still go in order. This is because `map()` is +/// still being called lazilly on each item, but we are popping items off the +/// back of the vector now, instead of shifting them from the front. +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) +/// .rev() { +/// println!("{:?}", pair); +/// } +/// ``` #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)]