当给定的枚举不是某种变体时,如何返回None?

Jam*_*lor 4 rust

我定义了以下枚举:

#[derive(Debug, Copy, Clone)]
struct Core;

#[derive(Debug, Copy, Clone)]
struct Mem;

#[derive(Debug, Copy, Clone)]
pub enum Atag {
    Core(Core),
    Mem(Mem),
    Cmd(&'static str),
    Unknown(u32),
    None,
}
Run Code Online (Sandbox Code Playgroud)

我想在这个enum上实现一个"过滤掉"某些枚举值的函数.我有以下内容:

impl Atag {
    /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
    pub fn core(self) -> Option<Core> {
        match self {
            Atag::Core => Some(self),
            _ => None
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我不知道为什么,但编译器抱怨:

error[E0532]: expected unit struct/variant or constant, found tuple variant `Atag::Core`
  --> src/main.rs:17:13
   |
17 |             Atag::Core => Some(self),
   |             ^^^^^^^^^^ not a unit struct/variant or constant
help: possible better candidate is found in another module, you can import it into scope
   |
1  | use Core;
   |
Run Code Online (Sandbox Code Playgroud)

我也尝试了一种比较方法:

pub fn core(self) -> Option<Core> {
    if self == Atag::Core {
        Some(self)
    } else {
        None
    }
}
Run Code Online (Sandbox Code Playgroud)

但编译器抱怨:

error[E0369]: binary operation `==` cannot be applied to type `Atag`
  --> src/main.rs:20:12
   |
20 |         if self == Atag::Core {
   |            ^^^^^^^^^^^^^^^^^^
   |
   = note: an implementation of `std::cmp::PartialEq` might be missing for `Atag`
Run Code Online (Sandbox Code Playgroud)

Mut*_*pus 5

我认为这只是模式匹配的限制,旨在防止意外行为.

Atagwith类型的完整"定义" CoreAtag::Core(raw::Core).显然,这些内容Core与你无关,但编译器需要知道所有内容都是"占用"的,因为编译器是规则的坚持者.解决这个问题的最简单方法是使用"任何模式",_就像你匹配非Core变体一样.

impl Atag {
    /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
    pub fn core(self) -> Option<Core> {
        match self {
            // The compiler now knows that a value is expected,
            // but isn't necessary for the purposes of our program.
            Atag::Core(_) => Some(self),
            _ => None
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要忽略多个值,您可以使用Something::Foo(_, _)- 变量中每个值的一个下划线,或Something::Foo(..)忽略所有值.

请记住,与其他语言不同,Rust枚举不仅仅是"不仅仅是"不同类型的集合.与枚举值相关联的数据是其中的一部分,就像结构的字段一样.所以self == Atag::Core这不是一个有意义的陈述,因为它忽略了与a相关的数据Core.A Foo(0)与a不同Foo(12),即使它们都是Foo变体.

我还要指出if let,就我所知,这是一个标准if语句的最接近的选项,而没有定义自定义is_core函数Atag(考虑到存在matchif let,基本上没有必要).

impl Atag {
    /// Returns `Some` if this is a `Core` ATAG. Otherwise returns `None`.
    pub fn core(self) -> Option<Core> {
        if let Atag::Core(_) = self {
            Some(self)
        } else {
            None
        }
    }
}
Run Code Online (Sandbox Code Playgroud)