diff options
| author | Waffle <waffle.lapkin@gmail.com> | 2020-03-13 11:51:55 +0300 |
|---|---|---|
| committer | Waffle <waffle.lapkin@gmail.com> | 2020-03-18 10:25:58 +0300 |
| commit | a5206f9749faf60f6b4163a526de9ad18241503e (patch) | |
| tree | 02efc5c900847a5b482fe140c92c87547013c65d /src/libcore | |
| parent | d939f708d960161d23b964309ba68ff207fc0ead (diff) | |
| download | rust-a5206f9749faf60f6b4163a526de9ad18241503e.tar.gz rust-a5206f9749faf60f6b4163a526de9ad18241503e.zip | |
add `Option::{zip,zip_with}` methods under "option_zip" gate
This commit introduces 2 methods - `Option::zip` and `Option::zip_with` with respective signatures: - zip: `(Option<T>, Option<U>) -> Option<(T, U)>` - zip_with: `(Option<T>, Option<U>, (T, U) -> R) -> Option<R>` Both are under the feature gate "option_zip". I'm not sure about the name "zip", maybe we can find a better name for this. (I would prefer `union` for example, but this is a keyword :( ) -------------------------------------------------------------------------------- Recently in a russian rust begginers telegram chat a newbie asked (translated): > Are there any methods for these conversions: > > 1. `(Option<A>, Option<B>) -> Option<(A, B)>` > 2. `Vec<Option<T>> -> Option<Vec<T>>` > > ? While second (2.) is clearly `vec.into_iter().collect::<Option<Vec<_>>()`, the first one isn't that clear. I couldn't find anything similar in the `core` and I've come to this solution: ```rust let tuple: (Option<A>, Option<B>) = ...; let res: Option<(A, B)> = tuple.0.and_then(|a| tuple.1.map(|b| (a, b))); ``` However this solution isn't "nice" (same for just `match`/`if let`), so I thought that this functionality should be in `core`.
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/lib.rs | 1 | ||||
| -rw-r--r-- | src/libcore/option.rs | 59 |
2 files changed, 60 insertions, 0 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a731766054..94fc2fd357a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -140,6 +140,7 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] +#![feature(option_zip)] #![feature(no_niche)] // rust-lang/rust#68303 #[prelude_import] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 9b32442371c..5db92a1b352 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -913,6 +913,65 @@ impl<T> Option<T> { pub fn replace(&mut self, value: T) -> Option<T> { mem::replace(self, Some(value)) } + + /// Zips `self` with another `Option`. + /// + /// Returns `Some((_, _))` when both `self` and `other` + /// are `Some(_)`, otherwise return `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_zip)] + /// let x = Some(1); + /// let y = Some("hi"); + /// let z = None::<u8>; + /// + /// assert_eq!(x.zip(y), Some((1, "hi"))); + /// assert_eq!(x.zip(z), None); + /// ``` + #[inline] + #[unstable(feature = "option_zip", issue = "none")] + pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> { + self.zip_with(other, |a, b| (a, b)) + } + + /// Zips `self` and another `Option` with function `f`. + /// + /// Returns `Some(_)` when both `self` and `other` + /// are `Some(_)`, otherwise return `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_zip)] + /// + /// #[derive(Debug, PartialEq)] + /// struct Point { + /// x: f64, + /// y: f64, + /// } + /// + /// impl Point { + /// fn new(x: f64, y: f64) -> Self { + /// Self { x, y } + /// } + /// } + /// + /// let x = Some(17.); + /// let y = Some(42.); + /// + /// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17., y: 42. })); + /// assert_eq!(x.zip_with(None, Point::new), None); + /// ``` + #[inline] + #[unstable(feature = "option_zip", issue = "none")] + pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R> + where + F: FnOnce(T, U) -> R, + { + Some(f(self?, other?)) + } } impl<T: Copy> Option<&T> { |
