В Rust перечисления (enums) могут хранить не только значения (variants), но и ассоциированные с ними данные (payload). Это делает их особенно удобными для создания алгебраических типов данных, например, для представления состояния или сообщений с параметрами. Например:
enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }
Для обработки таких enums обычно применяют оператор match, позволяющий распаковать вложенные значения каждого варианта:
let msg = Message::Move { x: 10, y: 20 }; match msg { Message::Quit => println!("Quit message"), Message::Move { x, y } => println!("Move to ({}, {})", x, y), Message::Write(text) => println!("Text: {}", text), Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b), }
Такой подход позволяет безопасно и явно обрабатывать все возможные случаи, что минимизирует ошибки в логике программы.
Почему в Rust не существует null для enums, и что вернет попытка сопоставления с несуществующим вариантом?
Частый неверный ответ: "Компилятор пропустит ошибку, если не обработать все варианты enum в match."
На самом деле компилятор выдаст ошибку, если не будут учтены все возможные варианты, либо потребует добавить catch-all (_). Например:
enum Status { Ok, Err(String) } let st = Status::Ok; match st { Status::Ok => println!("Ok"), // Если забыть Status::Err, компилятор пожалуется }
История В одном проекте при расширении enum не добавили обработку нового варианта в match во всех местах, где он использовался. Это привело к panic! в релизе, так как
matchне был исчерпывающим (exhaustive), при этом тесты покрывали не все кейсы.
История В другом случае попытались сравнить enum с помощью обычного
==без реализации PartialEq для сложных вариантов с ассоциированными данными, что вызвало неожиданную ошибку компиляции.
История Команда использовала catch-all (
_) для обработки variants, и позже, при добавлении новых вариантов, это привело к тому, что логика silently игнорировала новые случаи, что стало причиной сложных для поиска дефектов.