简体   繁体   中英

Is there a macro I can use to expect a variant of an enum and extract its data?

Given an enum like

struct Earth { water: usize }
struct Mars { redness: usize }

enum World {
    Mars(Mars),
    Earth(Earth),
}

A common pattern I write is

fn something_expecting_mars(planet: World) {
    let mars = match planet {
        World::Mars(data) => data,
        _ => panic!("Shouldn't be here now"),
    }
}

Is there a macro I can use to expect a variant of an enum and subsequently extract its data?

// rewriting to this
let mars = expect_v!(planet, World::Mars);

The standard library provides a macro for testing a match , but not one for extracting a value. However, it's fairly easy to write one:

macro_rules! expect_v {
    ($e:expr, $p:path) => {
        match $e {
            $p(value) => value,
            _ => panic!("expected {}", stringify!($p)),
        }
    };
}

Playground

As suggested in answers to the related question brought up in the comments, you might want to decouple value extraction from the panic. In that case, return an Option instead and let the callers panic if they wish by calling unwrap() :

macro_rules! extract {
    ($e:expr, $p:path) => {
        match $e {
            $p(value) => Some(value),
            _ => None,
        }
    };
}

// ...
fn something_expecting_mars(planet: World) {
    let mars = extract!(planet, World::Mars).unwrap();
}

Anything wrong with just using if let instead of match ?

mars = if let World::Mars(data) = planet { data } else { panic!("Woot woot")}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM