Объявление enum
enum объявляет тип, значения которого — фиксированный набор именованных вариантов:
enum Status {
ready,
failed,
}
Теперь Status — это тип с ровно двумя значениями: Status.ready и Status.failed. Ничто другое не может быть Status.
Грамматика намеренно крошечная:
enum Name {открывает объявление.- Каждая строка перечисляет одно имя варианта, через запятую.
}закрывает.
Никаких payload, никаких значений-дискриминаторов, никаких производных методов — это и удерживает enum в роли «маленького sum-типа» в Zero.
Использование enum
Назовите вариант, квалифицировав его типом enum:
let state: Status = Status.ready
Аннотация : Status необязательна, как только правая часть закрепляет тип; в большинстве случаев можно писать:
let state = Status.ready
и компилятор сам выведет тип Status.
Сравнение значений enum
Два значения enum равны, когда это один и тот же вариант:
if state == Status.ready {
check world.out.write("ready\n")
} else {
check world.out.write("not ready\n")
}
Это самый простой способ ветвиться по enum. Для исчерпывающего разбора — обработать каждый вариант явно — берите match:
match state {
.ready => { check world.out.write("ready\n") }
.failed => { check world.out.write("failed\n") }
}
Преимущество match перед if/else if проявится, когда позже вы добавите третий вариант. Компилятор покажет каждый match, где нет нового случая; цепочка if/else молча провалится в свой дефолтный бранч.
Choice и match разбирает match подробнее. Он работает и для enum, и для choice.
Разобранный пример
Официальный пример Zero ставит enum и choice рядом в одном файле:
Status в этом фрагменте ничего не делает — он стоит здесь ради контраста. Вариант choice привязывает payload (value, message) при матчинге; вариант enum не привязывает ничего, потому что привязывать нечего.
Enum vs Choice: короткое дерево решений
Короткое правило:
- Варианты — просто метки →
enum. - Варианты должны нести данные →
choice.
Если моделируете lifecycle-состояния и в итоге нужно прицепить сообщение об ошибке к состоянию «failed», переключайте тип с enum на choice. Каждый вариант получит тип payload, а нижестоящие arm match приобретут привязку для этого payload. Это рефакторинг, через который вас проведёт компилятор.
Конкретно:
// До — enum, без payload
enum Status {
ready,
failed,
}
// После — choice с payload на каждом варианте
choice Status {
ready: Void,
failed: String,
}
Варианты с payload Void в форме choice — это просто метки. Один и тот же логический набор состояний можно выразить и через enum, и через choice; выбирайте enum, когда вам действительно не нужно прикладывать данные.
Где это применяется
Несколько повседневных примеров, где enum — правильный ответ:
- Lifecycle без метаданных.
Loading,Ready,Empty— чистые состояния, без payload. - Режимы.
Read,Write,Appendдля режима открытия файла. - Направление.
North,South,East,West. - Уровень лога.
Trace,Debug,Info,Warn,Error. (Позже, возможно, захочется приложить сообщение — тогда вы переключитесь наchoice.) - День недели. Каноничный пример.
Везде, где иначе вы потянулись бы к магическим целочисленным константам (0 = pending, 1 = active, 2 = done), enum почти всегда понятнее.
Стиль
- Имена вариантов в нижнем регистре — это в духе Zero и согласовано с остальными идентификаторами в языке.
- Хвостовая запятая после последнего варианта — это нормально (и рекомендуется ради diff-дружелюбности — добавление нового варианта не трогает предыдущую строку).
- Держите списки enum небольшими. Если у вас дюжина вариантов и многим из них хочется payload — возможно, перед вами
choice— или повод пересмотреть дизайн, — а не более крупныйenum.
Дальше: Choice и Match
Естественный следующий шаг — более богатый родственник: choice и match, tagged-union тип Zero и подходящая ему конструкция pattern matching.
Часто задаваемые вопросы
Что такое enum в Zero?
enum объявляет тип, значения которого — один из фиксированного набора именованных вариантов: метки без какого-либо payload. Пример: enum Status { ready, failed }. Значение типа Status — это ровно Status.ready или Status.failed, и компилятор это обеспечивает.
Чем enum отличается от choice?
Варианты enum — это просто метки, без данных. choice — это tagged union: у каждого варианта есть связанный тип payload, например choice Result { ok: i32, err: String }. Используйте enum, когда случаи различаются только именем; используйте choice, когда каждый случай несёт дополнительную информацию.
Как проверить, какой вариант enum в значении?
Сравните значение с вариантом: if status == Status.ready { ... }. Для исчерпывающего ветвления по всем вариантам берите match — компилятор предупредит, если вы пропустили вариант, и это главная причина предпочесть match цепочкам if/else if, когда значение — это sum-тип.
Могут ли варианты enum иметь связанные значения в Zero?
Нет — для этого есть choice. enum намеренно минимальный sum-тип: каждый вариант — просто метка. Если нужно прицепить i32 или String к одному из вариантов, вы переросли enum и хотите choice.
Когда стоит использовать enum в Zero?
Используйте enum, когда значение должно быть ровно одним из маленького именованного набора состояний, и эти состояния не несут дополнительных данных. Примеры: день недели, цвет светофора, lifecycle-состояние без метаданных, уровень логирования. Если хочется прицепить данные к одному из вариантов — переключайтесь на choice.