在Rust中,有没有办法迭代枚举的值?

dou*_*qrd 40 iteration enums rust

我来自Java背景,我可能有类似的东西enum Direction { NORTH, SOUTH, EAST, WEST},我可以使用增强的for循环依次对每个值做一些事情,如:

for(Direction dir : Direction.values())  {
    //do something with dir
}
Run Code Online (Sandbox Code Playgroud)

我想用Rust枚举做类似的事情.

Vla*_*eev 29

不,没有.我认为这是因为Rust中的枚举比Java强大得多 - 它们实际上是完整的代数数据类型.例如,您希望如何迭代此枚举的值:

enum Option<T> {
    None,
    Some(T)
}
Run Code Online (Sandbox Code Playgroud)

它的第二个成员,Some不是静态常量 - 你用它来创建值Option<T>:

let x = Some(1);
let y = Some("abc");
Run Code Online (Sandbox Code Playgroud)

因此,没有理智的方法可以迭代任何枚举的值.

当然,我认为,可以在编译器中添加对静态枚举(即只包含静态项的枚举)的特殊支持,因此它会生成一些返回枚举值或静态向量的函数,但是我相信编译器的额外复杂性是不值得的.

如果您真的需要此功能,可以编写自定义语法扩展(请参阅问题).此扩展应接收标识符列表,并输出枚举和静态常量向量,并将这些标识符作为内容.常规宏也可以在某种程度上起作用,但据我记得你不能用多次性转录宏参数两次,所以你必须手动编写枚举元素两次,这是不方便的.

此问题也可能引起一些兴趣:#5417

当然,您总是可以编写代码,手动返回枚举元素列表.

  • 我恭敬地不同意所列举的枚举不值得.这是一个常见且有用的事情是_为什么它们被称为enums_!当然,代数的力量很大,但最常见情况的便利性也很好. (19认同)
  • @VladimirMatveev - 呃,很少应该手动构造,可以自动构建.有点编译器,不是吗?但我同意你的分析. (3认同)

A.B*_*.B. 29

如果枚举类似于C(如在您的示例中),那么您可以这样做:

use self::Direction::*;
use std::slice::Iter;

#[derive(Debug)]
pub enum Direction { North, South, East, West }

impl Direction {
    pub fn iterator() -> Iter<'static, Direction> {
        static DIRECTIONS: [Direction;  4] = [North, South, East, West];
        DIRECTIONS.into_iter()
    }
}


fn main() {
    for dir in Direction::iterator() {
        println!("{:?}", dir);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这种方法的问题是您需要使数组与枚举常量保持同步。如果您添加一个常量并忘记调整“iterator()”方法,则会出现错误。“strum”(或类似的库)解决了这个问题。 (7认同)

Jor*_*ack 14

现在,您可以使用Strum板条箱轻松地遍历枚举的值。

extern crate strum;
#[macro_use] extern crate strum_macros;

use strum::IntoEnumIterator;

#[derive(Display, EnumIter)]
enum Direction
{
    NORTH,
    SOUTH,
    EAST,
    WEST
}

fn main()
{
    for direction in Direction::iter()
    {
        println!("{}", direction);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

NORTH
SOUTH
EAST
WEST
Run Code Online (Sandbox Code Playgroud)

  • 还有[enum-iterator crate](https://crates.io/crates/enum-iterator),它通过“Sequence”特征和“all”函数提供类似的功能,并具有支持嵌套枚举的优点。 (2认同)

cam*_*ous 12

您可以使用关联的常量:

#[derive(Debug)]
enum Direction { North, South, East, West }

impl Direction {
    const VALUES: [Self; 4] = [Self::North, Self::South, Self::East, Self::West];
}

fn main() {
    for direction in Direction::VALUES {
        println!("{direction:?}");
    }
}
Run Code Online (Sandbox Code Playgroud)


phi*_*mue 8

我在箱子里plain_enum实现了基本功能.

它可用于声明类似C的枚举,如下所示:

#[macro_use]
extern crate plain_enum;

plain_enum_mod!(module_for_enum, EnumName {
    EnumVal1,
    EnumVal2,
    EnumVal3,
});
Run Code Online (Sandbox Code Playgroud)

然后允许您执行以下操作:

for value in EnumName::values() {
    // do things with value
}

let enummap = EnumName::map_from_fn(|value| {
    convert_enum_value_to_mapped_value(value)
})
Run Code Online (Sandbox Code Playgroud)