From 8eb0c0df0e8923a264d114291ab96e7bbfa13150 Mon Sep 17 00:00:00 2001 From: Karl Meakin Date: Thu, 17 Jun 2021 20:42:48 +0100 Subject: [PATCH] Document associativity of iterator folds. Document the associativity of `Iterator::fold` and `DoubleEndedIterator::rfold` and add examples demonstrating this. Add links to direct users to the fold of the opposite associativity. --- library/core/src/iter/traits/double_ended.rs | 9 +++++++- library/core/src/iter/traits/iterator.rs | 22 +++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index c302502b3b7e6..6d3ab788e5f48 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -248,6 +248,11 @@ pub trait DoubleEndedIterator: Iterator { /// Folding is useful whenever you have a collection of something, and want /// to produce a single value from it. /// + /// Note: `rfold()` combines elements in a *right-associative* fashion. For associative + /// operators like `+`, the order the elements are combined in is not important, but for non-associative + /// operators like `-` the order will affect the final result. + /// For a *left-associative* version of `rfold()`, see [`Iterator::fold()`]. + /// /// # Examples /// /// Basic usage: @@ -262,7 +267,8 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(sum, 6); /// ``` /// - /// This example builds a string, starting with an initial value + /// This example demonstrates the right-associative nature of `rfold()`: + /// it builds a string, starting with an initial value /// and continuing with each element from the back until the front: /// /// ``` @@ -276,6 +282,7 @@ pub trait DoubleEndedIterator: Iterator { /// /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))"); /// ``` + #[doc(alias = "foldr")] #[inline] #[stable(feature = "iter_rfold", since = "1.27.0")] fn rfold(mut self, init: B, mut f: F) -> B diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 78d317096b4f6..41d9993abaa4f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2083,6 +2083,11 @@ pub trait Iterator { /// Note: [`reduce()`] can be used to use the first element as the initial /// value, if the accumulator type and item type is the same. /// + /// Note: `fold()` combines elements in a *left-associative* fashion. For associative + /// operators like `+`, the order the elements are combined in is not important, but for non-associative + /// operators like `-` the order will affect the final result. + /// For a *right-associative* version of `fold()`, see [`DoubleEndedIterator::rfold()`]. + /// /// # Note to Implementors /// /// Several of the other (forward) methods have default implementations in @@ -2116,6 +2121,21 @@ pub trait Iterator { /// /// And so, our final result, `6`. /// + /// This example demonstrates the left-associative nature of `fold()`: + /// it builds a string, starting with an initial value + /// and continuing with each element from the front until the back: + /// + /// ``` + /// let numbers = [1, 2, 3, 4, 5]; + /// + /// let zero = "0".to_string(); + /// + /// let result = numbers.iter().fold(zero, |acc, &x| { + /// format!("({} + {})", acc, x) + /// }); + /// + /// assert_eq!(result, "(((((0 + 1) + 2) + 3) + 4) + 5)"); + /// ``` /// It's common for people who haven't used iterators a lot to /// use a `for` loop with a list of things to build up a result. Those /// can be turned into `fold()`s: @@ -2140,7 +2160,7 @@ pub trait Iterator { /// ``` /// /// [`reduce()`]: Iterator::reduce - #[doc(alias = "inject")] + #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn fold(mut self, init: B, mut f: F) -> B