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

时间:2018-03-23 03:17:48

标签: 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,
}

我想在这个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
        }
    }
}

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

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;
   |

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

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

但是编译器抱怨道:

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`

2 个答案:

答案 0 :(得分:5)

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

完整的定义&#34;类型为Atag的{​​{1}}为Core。显然,Atag::Core(raw::Core)的内容与你无关,但是编译器需要知道所有内容都是&#34;占...&#34;因为编译器是规则的坚持者。解决这个问题的最简单方法是使用&#34;任何模式&#34;,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 } } } - 变体中每个值使用一个下划线,或Something::Foo(_, _)忽略所有值。

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

我还想指出if let,据我所知,这是标准Foo语句的最接近的选项,而没有定义自定义if is_core上的函数(鉴于Atagmatch的存在,基本上没有必要)。

if let

答案 1 :(得分:0)

我需要这样的东西才能将功能很好地链接在一起。在这种情况下,您要返回展开的核心类型,而不仅仅是返回枚举。

我还发现不使用输入会更容易,因此接受了&self参数并返回了Option<&Core>。但是你可以两者兼有。

Rust convention具有as_X作为基于参考的转换,而into_X作为使用该值的转换。例如:

impl Atag {
    fn as_core(&self) -> Option<&Core> {
        if let Atag::Core(ref v) = self {
            Some(v)
        } else {
            None
        }
    }
    fn into_core(self) -> Option<Core> {
        if let Atag::Core(v) = self {
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    let c = Atag::Core(Core {});
    let m = Atag::Mem(Mem {});
    assert_eq!(c.as_core().map(|cc| "CORE_REF"), Some("CORE_REF"));
    assert_eq!(m.as_core().map(|cc| "CORE_REF"), None);
    // Consume c - we cant use it after here...
    assert_eq!(c.into_core().map(|cc| "NOM NOM CORE"), Some("NOM NOM CORE"));
    // Consume m - we cant use it after here...
    assert_eq!(m.into_core().map(|cc| "NOM NOM CORE"), None);
}