我来自Java背景,可能有类似的东西,enum Direction { NORTH, SOUTH, EAST, WEST}
并且可以使用增强的for循环依次处理每个值:
for(Direction dir : Direction.values()) {
//do something with dir
}
我想对Rust枚举做类似的事情。
我来自Java背景,可能有类似的东西,enum Direction { NORTH, SOUTH, EAST, WEST}
并且可以使用增强的for循环依次处理每个值:
for(Direction dir : Direction.values()) {
//do something with dir
}
我想对Rust枚举做类似的事情。
Answers:
不,没有。我认为这是因为Rust中的枚举比Java中的枚举要强大得多-它们实际上是成熟的代数数据类型。例如,您希望如何迭代此枚举的值:
enum Option<T> {
None,
Some(T)
}
?
它的第二个成员Some
不是静态常量-您可以使用它创建以下值Option<T>
:
let x = Some(1);
let y = Some("abc");
因此,没有一种明智的方法可以遍历任何枚举的值。
当然,我认为,可以在编译器中添加对静态枚举(即仅带有静态项目的枚举)的特殊支持,因此它将生成一些函数,这些函数返回带有它们的枚举或静态向量的值,但是我相信编译器中额外的复杂性是不值得的。
如果您确实需要此功能,则可以编写自定义语法扩展名(请参阅此问题)。此扩展名应接收标识符列表,并输出一个枚举和一个静态常量向量,并将这些标识符作为内容。常规宏也可以在某种程度上起作用,但是据我所知,您不能两次复制具有多重性的宏参数,因此您必须手动编写两次enum元素,这并不方便。
同样,这个问题可能引起一些关注:#5417
当然,您总是可以编写代码来手动返回枚举元素列表。
如果枚举类似于C(如您的示例所示),则可以创建static
每个变量的数组,并返回对它们的引用的迭代器:
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.iter()
}
}
fn main() {
for dir in Direction::iterator() {
println!("{:?}", dir);
}
}
如果使枚举实现Copy
,则可以使用Iterator::copied
并返回impl Trait
来获得值的迭代器:
impl Direction {
pub fn iterator() -> impl Iterator<Item = Direction> {
[North, South, East, West].iter().copied()
}
}
也可以看看:
我在板条箱中plain_enum
实现了基本功能。
它可以用来声明类似于C的枚举,如下所示:
#[macro_use]
extern crate plain_enum;
plain_enum_mod!(module_for_enum, EnumName {
EnumVal1,
EnumVal2,
EnumVal3,
});
然后允许您执行以下操作:
for value in EnumName::values() {
// do things with value
}
let enummap = EnumName::map_from_fn(|value| {
convert_enum_value_to_mapped_value(value)
})
如果您不想导入第三方板条箱,则可以创建自己的宏。这是我实现的方式(可能有一些方法可以改善这一点):
macro_rules! iterable_enum {
($visibility:vis, $name:ident, $($member:tt),*) => {
$visibility enum $name {$($member),*}
impl $name {
fn iterate() -> Vec<$name> {
vec![$($name::$member,)*]
}
}
};
($name:ident, $($member:tt),*) => {
iterable_enum!(, $name, $($member),*)
};
}
然后您可以执行以下操作:
iterable_enum!(pub, EnumName, Value1, Value2, Value3);
fn main() {
for member in EnumName::iterate() {
// ...
}
}
此实现仅限于简单的枚举。考虑以下枚举,您将如何对其进行迭代?:
enum MoreComplexEnum<T1, T2> {
One(T1),
Two(T2),
Other,
Both(T1, T2),
Error(String),
}
由于Rust中枚举的强大功能,很难实现完美可迭代的枚举,因为它们不像C或Java中的简单枚举。
Enum
特质存在一个问题,该特质可能可以被派发给类似for dir in Direction::values() { ... }
(也许)的东西。