【问题标题】:What is the idiomatic way of mapping a single enum variant into a Result in Rust?将单个枚举变体映射到 Rust 中的结果的惯用方法是什么?
【发布时间】:2026-01-31 01:20:06
【问题描述】:

我有一个枚举类型定义为

enum MyEnum {
    Foo(SomeType),
    Bar(SomethingElse),
    Baz(YetAnotherThing),
    ...
}

而且我经常需要在Result-returning 函数的上下文中匹配单个案例。更具体地说,我编写这样的代码:

impl MyEnum {
    fn as_foo(&self) -> Result<&SomeType, Error> {
        if let MyEnum::Foo(x) = y {
            Ok(&x)
        } else {
            Err(MismatchError)
        }
    }

    fn as_bar(&self) -> Result<&SomethingElse, Error> {
         ...
    }

    ...

}

这样我以后可以做

let x = myenum.as_foo()?

而不是更麻烦

if let MyEnum::Foo(x) = myenum {
    ...
} else {
    return Err(MismatchError);
}

肯定有比为每个可能的变体手写方法更有效的方法来获得这种效果吗?该语言中是否已经存在某些内容,还是我应该研究编写自己的宏?

我不清楚如何处理有多个字段或命名字段的情况。前者可能通过一个元组?后者我总是可以通过引入中间结构来减少。

【问题讨论】:

  • 我写了一个程序宏来自动为我生成这些访问器(is_fooas_foointo_foo),仅适用于单个成员变量的情况,但它仍然生成相同的您显示的代码。

标签: enums rust


【解决方案1】:

你可以用一个简单的访问器宏来做到这一点:

macro_rules! try_unpack {
    ($variant:path, $value:expr) => {
        if let $variant(x) = $value {
            x
        } else {
            return Err(MismatchError)
        }   
    }
}

struct SomeType;
struct SomethingElse;
struct YetAnotherThing;

enum MyEnum {
    Foo(SomeType),
    Bar(SomethingElse),
    Baz(YetAnotherThing)
}

struct MismatchError;

fn test(x: MyEnum) -> Result<i32, MismatchError> {
    let y: SomethingElse = try_unpack!(MyEnum::Bar, x);
    return 42;
}

【讨论】:

  • 我总是对隐藏控制流的宏感到不舒服。为什么不使用宏来生成 getter?