Skip to content

Commit 801a25a

Browse files
authored
Rollup merge of #69997 - WaffleLapkin:option_zip, r=LukasKalbertodt
add `Option::{zip,zip_with}` methods under "option_zip" gate This PR 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`.
2 parents ef7c8a1 + 121bffc commit 801a25a

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
#![feature(associated_type_bounds)]
141141
#![feature(const_type_id)]
142142
#![feature(const_caller_location)]
143+
#![feature(option_zip)]
143144
#![feature(no_niche)] // rust-lang/rust#68303
144145

145146
#[prelude_import]

src/libcore/option.rs

+57
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,63 @@ impl<T> Option<T> {
913913
pub fn replace(&mut self, value: T) -> Option<T> {
914914
mem::replace(self, Some(value))
915915
}
916+
917+
/// Zips `self` with another `Option`.
918+
///
919+
/// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
920+
/// Otherwise, `None` is returned.
921+
///
922+
/// # Examples
923+
///
924+
/// ```
925+
/// #![feature(option_zip)]
926+
/// let x = Some(1);
927+
/// let y = Some("hi");
928+
/// let z = None::<u8>;
929+
///
930+
/// assert_eq!(x.zip(y), Some((1, "hi")));
931+
/// assert_eq!(x.zip(z), None);
932+
/// ```
933+
#[unstable(feature = "option_zip", issue = "70086")]
934+
pub fn zip<U>(self, other: Option<U>) -> Option<(T, U)> {
935+
self.zip_with(other, |a, b| (a, b))
936+
}
937+
938+
/// Zips `self` and another `Option` with function `f`.
939+
///
940+
/// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some(f(s, o))`.
941+
/// Otherwise, `None` is returned.
942+
///
943+
/// # Examples
944+
///
945+
/// ```
946+
/// #![feature(option_zip)]
947+
///
948+
/// #[derive(Debug, PartialEq)]
949+
/// struct Point {
950+
/// x: f64,
951+
/// y: f64,
952+
/// }
953+
///
954+
/// impl Point {
955+
/// fn new(x: f64, y: f64) -> Self {
956+
/// Self { x, y }
957+
/// }
958+
/// }
959+
///
960+
/// let x = Some(17.5);
961+
/// let y = Some(42.7);
962+
///
963+
/// assert_eq!(x.zip_with(y, Point::new), Some(Point { x: 17.5, y: 42.7 }));
964+
/// assert_eq!(x.zip_with(None, Point::new), None);
965+
/// ```
966+
#[unstable(feature = "option_zip", issue = "70086")]
967+
pub fn zip_with<U, F, R>(self, other: Option<U>, f: F) -> Option<R>
968+
where
969+
F: FnOnce(T, U) -> R,
970+
{
971+
Some(f(self?, other?))
972+
}
916973
}
917974

918975
impl<T: Copy> Option<&T> {

0 commit comments

Comments
 (0)