#037 Mar 22, 2026

37. Option::zip

Need to combine two Option values into a pair? Option::zip merges them into a single Option<(A, B)> — if either is None, you get None back.

The problem

You have two optional values and need both to proceed. The classic approach uses nested matching:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let name: Option<&str> = Some("Alice");
let age: Option<u32> = Some(30);

// Nested match — gets unwieldy fast
let greeting = match name {
    Some(n) => match age {
        Some(a) => Some(format!("{n} is {a} years old")),
        None => None,
    },
    None => None,
};

assert_eq!(greeting, Some("Alice is 30 years old".to_string()));

The fix: Option::zip

Zip collapses two Options into one tuple:

1
2
3
4
5
6
let name: Option<&str> = Some("Alice");
let age: Option<u32> = Some(30);

let greeting = name.zip(age).map(|(n, a)| format!("{n} is {a} years old"));

assert_eq!(greeting, Some("Alice is 30 years old".to_string()));

One line instead of six. If either value is None, zip short-circuits to None:

1
2
3
4
let name: Option<&str> = Some("Alice");
let age: Option<u32> = None;

assert_eq!(name.zip(age), None);

Bonus: zip with and_then

You can chain zip into more complex pipelines:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn lookup_user(id: u32) -> Option<String> {
    if id == 1 { Some("Alice".to_string()) } else { None }
}

fn lookup_role(id: u32) -> Option<String> {
    if id == 1 { Some("Admin".to_string()) } else { None }
}

let result = lookup_user(1)
    .zip(lookup_role(1))
    .map(|(user, role)| format!("{user} ({role})"));

assert_eq!(result, Some("Alice (Admin)".to_string()));

Option::zip is stable since Rust 1.46 and works anywhere you need both-or-nothing semantics without the nesting.

← Previous 35. LazyLock Next → 36. Cow<str> — Clone on Write