diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 25be26491e3..c958289b2c9 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2104,6 +2104,43 @@ fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> LoopSt self.try_fold((), check(f)).break_value() } + /// Applies function to the elements of iterator and returns + /// the first non-none result or the first error. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_find)] + /// + /// let a = ["1", "2", "lol", "NaN", "5"]; + /// + /// let is_my_num = |s: &str, search: i32| -> Result { + /// Ok(s.parse::()? == search) + /// }; + /// + /// let result = a.iter().try_find(|&&s| is_my_num(s, 2)); + /// assert_eq!(result, Ok(Some(&"2"))); + /// + /// let result = a.iter().try_find(|&&s| is_my_num(s, 5)); + /// assert!(result.is_err()); + /// ``` + #[inline] + #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + fn try_find(&mut self, mut f: F) -> Result, E> + where + Self: Sized, + F: FnMut(&Self::Item) -> R, + R: Try, + { + self.try_for_each(move |x| match f(&x).into_result() { + Ok(false) => LoopState::Continue(()), + Ok(true) => LoopState::Break(Ok(x)), + Err(x) => LoopState::Break(Err(x)), + }) + .break_value() + .transpose() + } + /// Searches for an element in an iterator, returning its index. /// /// `position()` takes a closure that returns `true` or `false`. It applies diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 8e1273c3172..6f1d69821f5 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -85,6 +85,7 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] +#![feature(try_find)] #![feature(is_sorted)] #![feature(iter_once_with)] #![feature(lang_items)] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index cf28ec8a636..8b8dc941534 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1557,6 +1557,46 @@ fn half_if_even(x: &isize) -> Option { } } +#[test] +fn test_try_find() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().try_find(testfn), Ok(None)); + let xs: &[isize] = &[1, 2, 3, 4]; + assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2))); + let xs: &[isize] = &[1, 3, 4]; + assert_eq!(xs.iter().try_find(testfn), Err(())); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.try_find(testfn), Ok(Some(&2))); + assert_eq!(iter.try_find(testfn), Err(())); + assert_eq!(iter.next(), Some(&5)); + + fn testfn(x: &&isize) -> Result { + if **x == 2 { + return Ok(true); + } + if **x == 4 { + return Err(()); + } + Ok(false) + } +} + +#[test] +fn test_try_find_api_usability() -> Result<(), Box> { + let a = ["1", "2"]; + + let is_my_num = |s: &str, search: i32| -> Result { + Ok(s.parse::()? == search) + }; + + let val = a.iter().try_find(|&&s| is_my_num(s, 2))?; + assert_eq!(val, Some(&"2")); + + Ok(()) +} + #[test] fn test_position() { let v = &[1, 3, 9, 27, 103, 14, 11]; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1f20ebc01e9..39f6133f2a6 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] +#![feature(try_find)] #![feature(is_sorted)] #![feature(iter_once_with)] #![feature(pattern)]