Rollup merge of #87054 - kit-981:master, r=scottmcm
Add a `try_reduce` method to the Iterator trait Tracking issue: #87053
This commit is contained in:
commit
c223a1c109
@ -2216,6 +2216,86 @@ fn reduce<F>(mut self, f: F) -> Option<Self::Item>
|
||||
Some(self.fold(first, f))
|
||||
}
|
||||
|
||||
/// Reduces the elements to a single one by repeatedly applying a reducing operation. If the
|
||||
/// closure returns a failure, the failure is propagated back to the caller immediately.
|
||||
///
|
||||
/// The return type of this method depends on the return type of the closure. If the closure
|
||||
/// returns `Result<Self::Item, E>`, then this function will return `Result<Option<Self::Item>,
|
||||
/// E>`. If the closure returns `Option<Self::Item>`, then this function will return
|
||||
/// `Option<Option<Self::Item>>`.
|
||||
///
|
||||
/// When called on an empty iterator, this function will return either `Some(None)` or
|
||||
/// `Ok(None)` depending on the type of the provided closure.
|
||||
///
|
||||
/// For iterators with at least one element, this is essentially the same as calling
|
||||
/// [`try_fold()`] with the first element of the iterator as the initial accumulator value.
|
||||
///
|
||||
/// [`try_fold()`]: Iterator::try_fold
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Safely calculate the sum of a series of numbers:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iterator_try_reduce)]
|
||||
///
|
||||
/// let numbers: Vec<usize> = vec![10, 20, 5, 23, 0];
|
||||
/// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
|
||||
/// assert_eq!(sum, Some(Some(58)));
|
||||
/// ```
|
||||
///
|
||||
/// Determine when a reduction short circuited:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iterator_try_reduce)]
|
||||
///
|
||||
/// let numbers = vec![1, 2, 3, usize::MAX, 4, 5];
|
||||
/// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
|
||||
/// assert_eq!(sum, None);
|
||||
/// ```
|
||||
///
|
||||
/// Determine when a reduction was not performed because there are no elements:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iterator_try_reduce)]
|
||||
///
|
||||
/// let numbers: Vec<usize> = Vec::new();
|
||||
/// let sum = numbers.into_iter().try_reduce(|x, y| x.checked_add(y));
|
||||
/// assert_eq!(sum, Some(None));
|
||||
/// ```
|
||||
///
|
||||
/// Use a [`Result`] instead of an [`Option`]:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iterator_try_reduce)]
|
||||
///
|
||||
/// let numbers = vec!["1", "2", "3", "4", "5"];
|
||||
/// let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
|
||||
/// numbers.into_iter().try_reduce(|x, y| {
|
||||
/// if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
|
||||
/// });
|
||||
/// assert_eq!(max, Ok(Some("5")));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")]
|
||||
fn try_reduce<F, R>(&mut self, f: F) -> ChangeOutputType<R, Option<R::Output>>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item, Self::Item) -> R,
|
||||
R: Try<Output = Self::Item>,
|
||||
R::Residual: Residual<Option<Self::Item>>,
|
||||
{
|
||||
let first = match self.next() {
|
||||
Some(i) => i,
|
||||
None => return Try::from_output(None),
|
||||
};
|
||||
|
||||
match self.try_fold(first, f).branch() {
|
||||
ControlFlow::Break(r) => FromResidual::from_residual(r),
|
||||
ControlFlow::Continue(i) => Try::from_output(Some(i)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests if every element of the iterator matches a predicate.
|
||||
///
|
||||
/// `all()` takes a closure that returns `true` or `false`. It applies
|
||||
|
@ -454,6 +454,34 @@ fn half_if_even(x: &isize) -> Option<isize> {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_reduce() {
|
||||
let v: Vec<usize> = vec![1, 2, 3, 4, 5];
|
||||
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
|
||||
assert_eq!(sum, Some(Some(15)));
|
||||
|
||||
let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
|
||||
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
|
||||
assert_eq!(sum, None);
|
||||
|
||||
let v: Vec<usize> = Vec::new();
|
||||
let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
|
||||
assert_eq!(sum, Some(None));
|
||||
|
||||
let v = vec!["1", "2", "3", "4", "5"];
|
||||
let max = v.into_iter().try_reduce(|x, y| {
|
||||
if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
|
||||
});
|
||||
assert_eq!(max, Some(Some("5")));
|
||||
|
||||
let v = vec!["1", "2", "3", "4", "5"];
|
||||
let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
|
||||
v.into_iter().try_reduce(|x, y| {
|
||||
if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
|
||||
});
|
||||
assert_eq!(max, Ok(Some("5")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_len() {
|
||||
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
|
@ -56,6 +56,7 @@
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(iter_is_partitioned)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(iterator_try_reduce)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_pin)]
|
||||
#![feature(const_slice_from_raw_parts)]
|
||||
|
Loading…
Reference in New Issue
Block a user