简体   繁体   English

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

[英]How can I return None when a given enum is not a certain variant?

I have the following enum defined: 我定义了以下枚举:

#[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,
}

I would like to implement a function on this enum which "filters out" certain enum values. 我想在这个enum上实现一个“过滤掉”某些枚举值的函数。 I have the following: 我有以下内容:

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

I'm not sure why, but the compiler complains: 我不知道为什么,但编译器抱怨:

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

I also tried a comparison approach: 我也尝试了一种比较方法:

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

But the compiler complains: 但编译器抱怨:

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`

I think this is just a limitation of the pattern matching and is designed to prevent unexpected behavior. 我认为这只是模式匹配的限制,旨在防止意外行为。

The full "definition" of an Atag with type Core is Atag::Core(raw::Core) . 具有Core类型的Atag的完整“定义”是Atag::Core(raw::Core) Obviously, the contents of the Core are irrelevant to you, but the compiler needs to know that everything is "accounted for" because the compiler is a stickler for the rules. 显然, Core的内容与您无关,但编译器需要知道所有内容都“被占用”,因为编译器是规则的坚持者。 The easiest way to get around this is to use the "anything pattern", _ , much like you did to match non- Core variants. 解决这个问题的最简单方法是使用“任何模式”, _ ,就像你匹配非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
        }
    }
}

To ignore multiple values, you'd use Something::Foo(_, _) - one underscore for each value in the variant, or Something::Foo(..) to ignore everything. 要忽略多个值,您可以使用Something::Foo(_, _) - 变量中的每个值使用一个下划线,或者忽略所有内容的Something::Foo(..)

Remember that, unlike in some other languages, a Rust enum is not "just" a collection of different types. 请记住,与其他语言不同,Rust枚举不仅仅是“不仅仅是”不同类型的集合。 Data associated with an enum value is a part of it, just like the fields of a structure. 与枚举值相关联的数据是其中的一部分,就像结构的字段一样。 So self == Atag::Core isn't a meaningful statement because it ignores the data associated with a Core . 所以self == Atag::Core不是一个有意义的语句,因为它忽略了与Core相关的数据。 A Foo(0) is different than a Foo(12) , even if they're both of the Foo variant. Foo(0)Foo(12) ,即使它们都是Foo变体。

I'd also like to point out if let , which is - as far as I can tell - the closest option to a standard if statement without defining a custom is_core function on Atag (which, given the existence of match and if let , is basically unnecessary). 我还想指出, if let - 就我所知 - 是最接近标准if语句的选项而没有在Atag上定义一个自定义的is_core函数(假设存在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
        }
    }
}

I needed something like this to chain functions together nicely. 我需要这样的东西来很好地将函数链接在一起。 In that case, you want to return the unwrapped core type, rather than just the enum. 在这种情况下,您希望返回未包装的核心类型,而不仅仅是枚举。

I also found it easier to not consume the input, and so accepted a &self argument an returned an Option<&Core> . 我还发现不使用输入更容易,因此接受了一个&self参数并返回了一个Option<&Core> But you can have both. 但你可以同时拥有两者。

The Rust convention has as_X as the reference-based conversion and into_X as the conversion that consumes the value. Rust约定as_X作为基于引用的转换,将into_X作为消耗该值的转换。 For example: 例如:

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

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

相关问题 如何将类型声明为“枚举变体之一或无”? - How do I declare a type as "one of an enum variant or a None"? 如何对枚举进行变异,然后返回对枚举变体的引用? - How do I mutate an enum and then return a reference to an enum variant? 如何动态确定枚举的变体 - How can I dynamically determine the variant of an enum 如何根据与变体中的类型匹配的泛型类型选择枚举变体? - How can I select an enum variant based on a generic type that matches a type inside the variant? 如何在将字段移动到新变体时更改枚举变体? - How can I change enum variant while moving the field to the new variant? 仅当字段是某个枚举变体时才为结构定义方法? - Defining a method for a struct only when a field is a certain enum variant? 如何存储枚举,以便仅通过识别变体就可以检索它? - How can I store an enum so I can retrieve it by only identifying the variant? 如何在不包含枚举变量名称的情况下序列化枚举? - How do I serialize an enum without including the name of the enum variant? 是否有一个宏可以用来期待枚举的变体并提取其数据? - Is there a macro I can use to expect a variant of an enum and extract its data? 如何使用 serde 反序列化为特定的枚举变体? - How do I use serde to deserialize into a specific enum variant?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM