如何对枚举成员进行分组但保持匹配详尽性检查

问题描述 投票:0回答:2

在 Rust 中,有没有一种方法可以对枚举成员进行“分组”,以便我可以获得谓词函数并在匹配语句中使用该谓词?

假设我有这个枚举:

enum Number {
  One,
  Two,
  Three,
  Four,
  Five,
  Six
}

这个谓词:

impl Number {
  fn is_prime(&self) -> bool {
    self == Number::Two || self == Number::Three || self == Number::Five
  }
}

然后我的问题是,我的代码库周围有几个匹配语句,如果数字是素数,它们会以不同的方式处理事情:

match number {
  Number::Two | Number::Three | Number::Five => {/* do something for primes*/}
  Number::One => ...
  Number::Four => ...
  Number::Six => ... 
}

我只想知道什么是素数的真相来源。当然,我可以在每个匹配语句之前添加谓词检查:

if number.is_prime() {
  /* do something for primes*/
} else {
  match number {
    Number::One => ...
    Number::Four => ...
    Number::Six => ...
    _ => {} // should never happen
  }
}

但是后来我失去了详尽性检查。我需要添加一个包罗万象的手臂,它不能为我提供编译安全性,以确保后来将成员添加到

Number
的任何人都必须在每个
match
语句中显式处理它。

理想情况下我想做这样的事情:

match number {
  is_prime() => {/* do something for primes*/}
  Number::One => ...
  Number::Four => ...
  Number::Six => ... 
}

有没有办法达到同样的目标?我想应该有一种方法可以通过宏来做到这一点,但我尽量避免使用宏,因为它们使代码不那么明确。

rust enums predicate
2个回答
2
投票

你可以制作一个宏:

#[macro_export]
macro_rules! primes {
    () => {
        $crate::Number::Two | $crate::Number::Three | $crate::Number::Five
    };
}

impl Number {
    pub fn factors(&self) -> u8 {
        use Number::*;
        match self {
            primes!() => 2,
            One => 1,
            Four => 3,
            Six => 4,
        }
    }
}

此宏假设

Number
在板条箱根中公开可用。如果在其他地方,请使用适当的路径。我认为没有办法避免为每个变体编写整个路径,因为模式中不能有
use
语句,尽管如果它非常长,您可以仅为路径部分创建另一个宏。 更多关于
$crate
的信息请点击此处。

从好的方面来看,它确实可以作为更大模式的一部分:

primes!() | Number::One

0
投票

如果您的组不同,您可以添加另一层枚举:

enum Numbers {
    Prime(Prime),
    NonPrime(NonPrime),
}
enum Prime {
    Two,
    Three,
    Five,
}
enum NonPrime {
    One,
    Four,
    Six,
}

然后就可以在外层搭配了:

use Number::*;
use Prime::*;
use NonPrime::*;
match number {
    Prime(_) => todo!("do something for primes"),
    NonPrime(One) => todo!("do something for one"),
    NonPrime(_) => todo!("do something for other non primes"),
}
© www.soinside.com 2019 - 2024. All rights reserved.