代码之家  ›  专栏  ›  技术社区  ›  James Taylor

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

  •  4
  • James Taylor  · 技术社区  · 6 年前

    我定义了以下枚举:

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

    我想在此枚举上实现一个函数,用于“过滤”某些枚举值。我有以下几点:

    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 回复  |  直到 5 年前
        1
  •  5
  •   Shepmaster Lukas Kalbertodt    6 年前

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

    完整的“定义” Atag 带类型 Core Atag::Core(raw::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(_, _) -变量中的每个值都有一个下划线,或 Something::Foo(..) 忽视一切。

    记住,与其他一些语言不同,Rust枚举“不仅仅”是不同类型的集合。与枚举值关联的数据是它的一部分,就像结构的字段一样。所以 self == Atag::Core 不是有意义的语句,因为它忽略与 果心 。A. Foo(0) 与a不同 Foo(12) ,即使他们都是 Foo 变种

    我还想指出 if let ,据我所知,这是最接近标准的选项 if 语句而不定义自定义 is_core 功能开启 Atag公司 (鉴于 match 如果让 ,基本上没有必要)。

    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
            }
        }
    }
    
        2
  •  0
  •   Shepmaster Lukas Kalbertodt    5 年前

    我需要这样的东西来很好地将函数链接在一起。在这种情况下,您希望返回未包装的核心类型,而不仅仅是枚举。

    我还发现不使用输入更容易,因此接受了 &self 参数an返回了 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);
    }