简体   繁体   English

是否有一个宏可以用来期待枚举的变体并提取其数据?

[英]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() :在这种情况下,请返回一个Option并让调用者在他们愿意的情况下通过调用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 ?仅使用if let而不是match有什么问题吗?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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