Skip to content

Commit 0a58f58

Browse files
committed
Auto merge of #63177 - MOZGIII:find-result, r=Amanieu
Add Iterator::try_find I found a need for this fn, and created this PR. Tracking issue: #63178 I did a fair amount of thinking about the function name, and settled on the current one. I don't see other anything else that's non-trivial here, but I'm open for debate. I just want this functionality to be there. It couples with the `collect` trick for collecting `Result<Vec<T>, E>` from `Iterator<Item = Result<T, E>>`. UPD: I've already looked at `fallible_iterator` crate, but I don't think it supports my use case. The main problem is that I can't construct a failable iterator. I have a regular iterator, and I just need to apply a predicate that can fail via `find` method. UPD: `fallible_iterator` would work, but it's not elegant cause I'd have to make a failable iterator by mapping iterator with `Result::Ok` first.
2 parents 766fba3 + 5446cc9 commit 0a58f58

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

Diff for: src/libcore/iter/traits/iterator.rs

+37
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,43 @@ pub trait Iterator {
21042104
self.try_fold((), check(f)).break_value()
21052105
}
21062106

2107+
/// Applies function to the elements of iterator and returns
2108+
/// the first non-none result or the first error.
2109+
///
2110+
/// # Examples
2111+
///
2112+
/// ```
2113+
/// #![feature(try_find)]
2114+
///
2115+
/// let a = ["1", "2", "lol", "NaN", "5"];
2116+
///
2117+
/// let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
2118+
/// Ok(s.parse::<i32>()? == search)
2119+
/// };
2120+
///
2121+
/// let result = a.iter().try_find(|&&s| is_my_num(s, 2));
2122+
/// assert_eq!(result, Ok(Some(&"2")));
2123+
///
2124+
/// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
2125+
/// assert!(result.is_err());
2126+
/// ```
2127+
#[inline]
2128+
#[unstable(feature = "try_find", reason = "new API", issue = "63178")]
2129+
fn try_find<F, E, R>(&mut self, mut f: F) -> Result<Option<Self::Item>, E>
2130+
where
2131+
Self: Sized,
2132+
F: FnMut(&Self::Item) -> R,
2133+
R: Try<Ok = bool, Error = E>,
2134+
{
2135+
self.try_for_each(move |x| match f(&x).into_result() {
2136+
Ok(false) => LoopState::Continue(()),
2137+
Ok(true) => LoopState::Break(Ok(x)),
2138+
Err(x) => LoopState::Break(Err(x)),
2139+
})
2140+
.break_value()
2141+
.transpose()
2142+
}
2143+
21072144
/// Searches for an element in an iterator, returning its index.
21082145
///
21092146
/// `position()` takes a closure that returns `true` or `false`. It applies

Diff for: src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
#![feature(extern_types)]
8686
#![feature(fundamental)]
8787
#![feature(intrinsics)]
88+
#![feature(try_find)]
8889
#![feature(is_sorted)]
8990
#![feature(iter_once_with)]
9091
#![feature(lang_items)]

Diff for: src/libcore/tests/iter.rs

+40
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,46 @@ fn test_find_map() {
15571557
}
15581558
}
15591559

1560+
#[test]
1561+
fn test_try_find() {
1562+
let xs: &[isize] = &[];
1563+
assert_eq!(xs.iter().try_find(testfn), Ok(None));
1564+
let xs: &[isize] = &[1, 2, 3, 4];
1565+
assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2)));
1566+
let xs: &[isize] = &[1, 3, 4];
1567+
assert_eq!(xs.iter().try_find(testfn), Err(()));
1568+
1569+
let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
1570+
let mut iter = xs.iter();
1571+
assert_eq!(iter.try_find(testfn), Ok(Some(&2)));
1572+
assert_eq!(iter.try_find(testfn), Err(()));
1573+
assert_eq!(iter.next(), Some(&5));
1574+
1575+
fn testfn(x: &&isize) -> Result<bool, ()> {
1576+
if **x == 2 {
1577+
return Ok(true);
1578+
}
1579+
if **x == 4 {
1580+
return Err(());
1581+
}
1582+
Ok(false)
1583+
}
1584+
}
1585+
1586+
#[test]
1587+
fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> {
1588+
let a = ["1", "2"];
1589+
1590+
let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
1591+
Ok(s.parse::<i32>()? == search)
1592+
};
1593+
1594+
let val = a.iter().try_find(|&&s| is_my_num(s, 2))?;
1595+
assert_eq!(val, Some(&"2"));
1596+
1597+
Ok(())
1598+
}
1599+
15601600
#[test]
15611601
fn test_position() {
15621602
let v = &[1, 3, 9, 27, 103, 14, 11];

Diff for: src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![feature(flt2dec)]
1212
#![feature(fmt_internals)]
1313
#![feature(hashmap_internals)]
14+
#![feature(try_find)]
1415
#![feature(is_sorted)]
1516
#![feature(iter_once_with)]
1617
#![feature(pattern)]

0 commit comments

Comments
 (0)