1. 1. Introduction
  2. 2. Введение
  3. 3. C чего начать
  4. 4. Изучение Rust
    1. 4.1. Угадайка
    2. 4.2. Обедающие философы
    3. 4.3. Вызов кода на Rust из других языков
  5. 5. Синтаксис и семантика
    1. 5.1. Связывание имён
    2. 5.2. Функции
    3. 5.3. Простые типы
    4. 5.4. Комментарии
    5. 5.5. Конструкция `if`
    6. 5.6. Циклы
    7. 5.7. Владение
    8. 5.8. Ссылки и заимствование
    9. 5.9. Время жизни
    10. 5.10. Изменяемость
    11. 5.11. Структуры
    12. 5.12. Перечисления
    13. 5.13. Конструкция `match`
    14. 5.14. Шаблоны сопоставления `match`
    15. 5.15. Синтаксис методов
    16. 5.16. Вектора
    17. 5.17. Строки
    18. 5.18. Обобщённое программирование
    19. 5.19. Типажи
    20. 5.20. Типаж `Drop`
    21. 5.21. Конструкция `if let`
    22. 5.22. Типажи-объекты
    23. 5.23. Замыкания
    24. 5.24. Универсальный синтаксис вызова функций
    25. 5.25. Контейнеры и модули
    26. 5.26. `const` и `static`
    27. 5.27. Атрибуты
    28. 5.28. Псевдонимы типов
    29. 5.29. Приведение типов
    30. 5.30. Ассоциированные типы
    31. 5.31. Безразмерные типы
    32. 5.32. Перегрузка операций
    33. 5.33. Преобразования при разыменовании
    34. 5.34. Макросы
    35. 5.35. Сырые указатели
    36. 5.36. Небезопасный код
  6. 6. Эффективное использование Rust
    1. 6.1. Стек и куча
    2. 6.2. Тестирование
    3. 6.3. Условная компиляция
    4. 6.4. Документация
    5. 6.5. Итераторы
    6. 6.6. Многозадачность
    7. 6.7. Обработка ошибок
    8. 6.8. Выбор гарантий
    9. 6.9. Интерфейс внешних функций
    10. 6.10. Типажи `Borrow` и `AsRef`
    11. 6.11. Каналы сборок
    12. 6.12. Using Rust without the standard library
  7. 7. Нестабильные возможности Rust
    1. 7.1. Плагины к компилятору
    2. 7.2. Встроенный ассемблерный код
    3. 7.3. Без stdlib
    4. 7.4. Внутренние средства
    5. 7.5. Элементы языка
    6. 7.6. Продвинутое руководство по компоновке
    7. 7.7. Тесты производительности
    8. 7.8. Синтаксис упаковки и шаблоны `match`
    9. 7.9. Шаблоны `match` для срезов
    10. 7.10. Ассоциированные константы
    11. 7.11. Пользовательские менеджеры памяти
  8. 8. Глоссарий
  9. 9. Syntax Index
  10. 10. Библиография

Перечисления

В Rust перечисление (enum) — это тип данных, который представляет собой один из нескольких возможных вариантов. Каждый вариант в перечислении может быть также связан с другими данными:

enum Message {
    Quit,
    ChangeColor(i32, i32, i32),
    Move { x: i32, y: i32 },
    Write(String),
}Run

Синтаксис для объявления вариантов схож с синтаксисом для объявления структур: у вас могут быть варианты без данных (как unit-подобные структуры), варианты с именованными данными и варианты с безымянными данными (подобно кортежным структурам). Варианты перечисления имеют один и тот же тип, и в отличии от структур не являются определением отдельных типов. Значение перечисления может соответствовать любому из вариантов. Из-за этого перечисления иногда называют тип-сумма (sum-type): множество возможных значений перечисления — это сумма множеств возможных значений каждого варианта.

Мы используем синтаксис :: чтобы использовать имя каждого из вариантов. Их область видимости ограничена именем самого перечисления. Это позволяет использовать оба варианта из примера ниже совместно:

let x: Message = Message::Move { x: 3, y: 4 };

enum BoardGameTurn {
    Move { squares: i32 },
    Pass,
}

let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 };Run

Оба варианта имеют одинаковое имя Move, но поскольку область видимости каждого из них ограничена именем соответствующего перечисления, они могут быть использованы без конфликтов.

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

fn process_color_change(msg: Message) {
    let Message::ChangeColor(r, g, b) = msg; // ошибка времени компиляции
}Run

То, что пользовательские типы по умолчанию не поддерживают операции, может показаться довольно ограниченным. Но это ограничение, которое мы всегда можем преодолеть. Есть два способа: реализовать операцию самостоятельно, или воспользоваться сопоставлением с образцом с помощью match, о котором вы узнаете в следующем разделе. Пока мы еще недостаточно знаем Rust, чтобы реализовывать операции, но мы научимся делать это в разделе traits.

Конструкторы как функции

Конструктор перечисления может быть также использован как обычная функция. Например:

let m = Message::Write("Hello, world".to_string());Run

тоже самое, что и

fn foo(x: String) -> Message {
    Message::Write(x)
}

let x = foo("Hello, world".to_string());Run

На данный момент это не так уж и полезно для нас, но когда мы перейдем к замыканиям, мы поговорим о передаче функций в роли аргумента другой функции. Например, с помощью итераторов мы можем преобразовывать вектор строк в вектор состоящий из Message::Write:


let v = vec!["Hello".to_string(), "World".to_string()];

let v1: Vec<Message> = v.into_iter().map(Message::Write).collect();Run