Search code examples
rustenumspattern-matching

Match two enum variants in one arm, binding field of one variant using Option?


I'd like to match two variants of an enum in one match arm. There is one field that is "the same" in each, meaning that it has the same type, name and semantic meaning. (field0: i32 in the example below.) I'd like to bind a local &mut i32 to field0 of the given variant. One variant also has a field that is not "shared" by the other. (field1: String in the example.) This I would like to bind to a local Option<&mut String>. Is there a neat way to do this?

enum Enum {
    Variant0 { field0: i32, field1: String },
    Variant1 { field0: i32 },
    Variant2,
}

fn mutate(value: &mut Enum) {
    match value {
        // Hopefully some pattern matching magic
        // to get a local &mut i32 and a local
        // Option<&mut String>.
    }
}

fn main() {
    mutate(&mut Enum::Variant0 {
        field0: 123,
        field1: "hello".to_string(),
    });

    mutate(&mut Enum::Variant1 { field0: 456 });
}

Solution

  • You can make field0 of both variants into the same binding with |.

    match value {
        Variant0 { field0, .. } | Variant1 { field0 } => println!("{field0}"),
        _ => (),
    }
    

    However, your other requirement of field1 doesn't really fit into this syntax, so you need to do it manually. If you only needed an & reference, you could do it in two match expressions, but that is unlikely to be any prettier.

    let (field0, field1) = match value {
        Variant0 { field0, field1 } => (field0, Some(field1)),
        Variant1 { field0 } => (field0, None),
        Variant2 => return,
    };
    println!("{field0}, {field1:?}");