Подтвердить что ты не робот

В Rust есть способ перебора значений enum?

Я исхожу из фона Java, и у меня может быть что-то вроде enum Direction { NORTH, SOUTH, EAST, WEST}, и я мог бы что-то сделать с каждым из значений в свою очередь с расширенным циклом, например:

for(Direction dir : Direction.values())  {
    //do something with dir
}

Я хотел бы сделать аналогичную вещь с перечислениями Rust.

4b9b3361

Ответ 1

Нет, нет. Я думаю, это связано с тем, что перечисления в Rust намного мощнее, чем на Java - они на самом деле являются полноценными алгебраическими типами данных. Например, как бы вы ожидали итерации над значениями этого перечисления:

enum Option<T> {
    None,
    Some(T)
}

?

Его второй член Some не является статической константой - вы используете его для создания значений Option<T>:

let x = Some(1);
let y = Some("abc");

Таким образом, нет здравого смысла, вы можете перебирать значения любого перечисления.

Конечно, я думаю, можно было бы добавить специальную поддержку для статических перечислений (то есть перечисления с только статическими элементами) в компилятор, поэтому он будет генерировать некоторую функцию, возвращающую значения перечислимого или статического вектора с ними, но я считаю, что дополнительная сложность в компиляторе просто не стоит того.

Если вы действительно хотите эту функциональность, вы можете написать собственное расширение синтаксиса (см. этот выпуск). Это расширение должно получать список идентификаторов и выводить перечисление и статический вектор констант с этими идентификаторами в качестве содержимого. Регулярный макрос также будет работать в некоторой степени, но, насколько я помню, вы не можете дважды транскрибировать макросы с множественностью, поэтому вам придется вручную писать элементы перечисления вручную, что не удобно.

Также этот вопрос может представлять определенный интерес: # 5417

И, конечно, вы всегда можете написать код, который вручную возвращает список элементов перечисления.

Ответ 2

Если перечисление C-like (как в вашем примере), вы можете сделать это:

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

Ответ 3

Я реализовал базовые функции в crate plain_enum.

Его можно использовать для объявления C-like перечисления следующим образом:

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