diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 31f77f92435d8..f039d1730eb3b 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1745,6 +1745,38 @@ pub trait Iterator { }).break_value() } + /// Applies function to the elements of iterator and returns + /// the first non-none result. + /// + /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`. + /// + /// + /// # Examples + /// + /// ``` + /// #![feature(iterator_find_map)] + /// let a = ["lol", "NaN", "2", "5"]; + /// + /// let mut first_number = a.iter().find_map(|s| s.parse().ok()); + /// + /// assert_eq!(first_number, Some(2)); + /// ``` + #[inline] + #[unstable(feature = "iterator_find_map", + reason = "unstable new API", + issue = "49602")] + fn find_map(&mut self, mut f: F) -> Option where + Self: Sized, + F: FnMut(Self::Item) -> Option, + { + self.try_for_each(move |x| { + match f(x) { + Some(x) => LoopState::Break(x), + None => LoopState::Continue(()), + } + }).break_value() + } + /// 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/tests/iter.rs b/src/libcore/tests/iter.rs index a962efadd64e9..2abac0cf1d5b9 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1146,6 +1146,33 @@ fn test_find() { assert!(v.iter().find(|&&x| x % 12 == 0).is_none()); } +#[test] +fn test_find_map() { + let xs: &[isize] = &[]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[3, 5]; + assert_eq!(xs.iter().find_map(half_if_even), None); + let xs: &[isize] = &[4, 5]; + assert_eq!(xs.iter().find_map(half_if_even), Some(2)); + let xs: &[isize] = &[3, 6]; + assert_eq!(xs.iter().find_map(half_if_even), Some(3)); + + let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7]; + let mut iter = xs.iter(); + assert_eq!(iter.find_map(half_if_even), Some(1)); + assert_eq!(iter.find_map(half_if_even), Some(2)); + assert_eq!(iter.find_map(half_if_even), Some(3)); + assert_eq!(iter.next(), Some(&7)); + + fn half_if_even(x: &isize) -> Option { + if x % 2 == 0 { + Some(x / 2) + } else { + None + } + } +} + #[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 1a68f04532d20..6f6105553d4de 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -48,6 +48,7 @@ #![feature(atomic_nand)] #![feature(reverse_bits)] #![feature(inclusive_range_fields)] +#![feature(iterator_find_map)] extern crate core; extern crate test;