JavaRush /Курсы /Swift SELF /enum и cases: синтаксис и назначение

enum и cases: синтаксис и назначение

Swift SELF
25 уровень , 0 лекция
Открыта

1. Проблема «значений по договорённости»

Когда программа маленькая, хочется хранить «состояния» и «режимы» как строки или числа: "admin", "guest", "exit", 1, 2, 3. Это кажется быстрым и простым… ровно до момента, пока где-то в коде не появится "admni" (опечатка) или 4 (никто уже не помнит, что это значит), и программа начнёт вести себя как кот, который делает вид, что вас не знает.

enum (enumeration, перечисление) — это способ сказать компилятору: «Смотри, допустимые варианты строго вот эти, ничего другого быть не может». И тогда компилятор становится вашим самым занудным, но полезным другом: он не даст присвоить «левое» значение и будет заставлять вас обрабатывать варианты явно.

Сравним подходы в одной маленькой таблице:

Подход Что хранится в переменной Плюсы Минусы
«строки по договорённости» String (например "exit") быстро начать опечатки, нет контроля вариантов, трудно расширять безопасно
Int «коды» Int (например 1 = exit) быстро и компактно магические числа, забывается смысл, легко перепутать
enum один из заранее перечисленных case типобезопасность, читаемость, помощь компилятора надо один раз объявить тип (но это «плата за порядок»)

2. Что такое enum в Swift: фиксированный набор вариантов

Сейчас введём определение максимально по-человечески. enum — это тип, значения которого могут быть только одним из перечисленных вариантов (case). Это как меню в кафе: вы можете выбрать «чай» или «кофе», но не «криптовалюту» — даже если очень уверенно попросите.

В рамках этой лекции мы рассматриваем самые простые enum: без привязки к строкам/числам и без «дополнительных данных» внутри case. Наша цель — уверенно писать синтаксис enum, создавать значения, хранить их и передавать в функции.

Простейший пример:

import Foundation

enum Direction {
    case north
    case south
    case east
    case west
}

let d: Direction = .north
print(d) // north

Здесь важное: d не может стать “north-east” или "north" строкой. Только один из четырёх case — и точка.

3. Синтаксис и использование enum в коде

Синтаксис объявления: enum и case

Прежде чем вы начнёте использовать enum в задачах и проектах, важно привыкнуть к его «внешности». Объявление enum выглядит похоже на struct: сначала ключевое слово, затем имя типа, затем тело в фигурных скобках. Внутри — список case, то есть вариантов.

В Swift есть две популярные формы записи: по одному case на строку (очень читаемо) и компактная запись через запятую (короче). По смыслу они одинаковые.

Полная форма:

import Foundation

enum UserRole {
    case guest
    case member
    case admin
}

Компактная форма:

import Foundation

enum UserRole {
    case guest, member, admin
}

Рекомендации по именованию тут такие же, как у типов и переменных. Имя enum — это тип, поэтому UpperCamelCase. Имена cases — это варианты, поэтому lowerCamelCase. Так код читается естественно, и Swift-стиль получается «родным».

Создание значения: UserRole.admin и синтаксис .admin

Когда вы впервые видите .admin, возникает вопрос: «Почему точка? Это что, доступ к свойству?». В некотором смысле — да: case действительно является членом типа, и это можно воспринимать как «статический член».

В Swift принят удобный стиль: если компилятор уже знает тип, можно писать case через leading dot (.admin) вместо UserRole.admin. Эта идея тесно связана с тем, что case — член типа, а не «просто слово».

Посмотрим на оба варианта:

import Foundation

enum UserRole { case guest, member, admin }

let a = UserRole.admin
let b: UserRole = .admin

print(a) // admin
print(b) // admin

Почему во втором случае можно .admin? Потому что мы явно указали тип переменной b: UserRole. У переменной есть контекст, и компилятор понимает, что .admin относится именно к UserRole.

А вот так — нельзя, потому что нет контекста:

import Foundation

enum UserRole { case guest, member, admin }

// let x = .admin // ❌ ошибка: компилятор не знает, чей это case

И это справедливо: .admin может существовать в десятке разных enum’ов, и компилятор не обязан угадывать ваши мысли (иначе это был бы уже психологический сервис, а не компилятор).

enum как обычное значение: переменные, массивы и словари

Новичкам иногда кажется, что enum — это что-то «для switch» и больше ни для чего. На деле enum — это обычное значение языка: вы можете хранить его в переменной, класть в массив, передавать в словарь, возвращать из функции. Это такой же «кусочек данных», как Int или String, просто с ограниченным набором возможных значений.

Пример с массивом:

import Foundation

enum PaymentMethod { case cash, card }

let methods: [PaymentMethod] = [.cash, .card, .cash]
print(methods.count) // 3

Пример со словарём (ключ — String, значение — enum):

import Foundation

enum ThemeMode { case light, dark }

let userSettings: [String: ThemeMode] = [
    "alex": .dark,
    "kate": .light
]

print(userSettings["alex"]!) // dark

Да, тут стоит !, и в реальном коде мы бы так не делали без проверки. Но идея примера простая: enum хранится как значение, и словарь спокойно его принимает.

Передача enum в функцию: читаемость и меньше ошибок

Функции — идеальное место, чтобы почувствовать пользу enum. Когда параметр функции имеет тип enum, вы больше не принимаете «абстрактную строку», в которой может быть что угодно. Вы принимаете один из допустимых вариантов. Это резко уменьшает число проверок, опечаток и «непонятных состояний».

Пример: печатаем приветствие по роли.

import Foundation

enum UserRole { case guest, member, admin }

func printGreeting(for role: UserRole) {
    print("Hello, \(role)!")
}

printGreeting(for: .admin) // Hello, admin!

Обратите внимание: в вызове мы пишем .admin, потому что тип параметра role: UserRole задаёт контекст, и это читается красиво. Именно такой leading dot синтаксис стал стандартным способом упоминать enum cases в местах, где тип уже известен.

4. Мини-пример: команды CLI через enum

Сейчас будет небольшой, но очень практичный мостик к учебному CLI-приложению. Представьте, что пользователь вводит команду: help, list, exit. Пока что (наивный подход) мы могли бы сравнивать строки. Но уже на этом этапе полезно сделать шаг к типобезопасности: описать набор команд через enum.

Важно: в этой лекции мы не привязываем команды к строкам автоматически и не используем «продвинутые» техники. Мы просто моделируем допустимые варианты и вручную переводим строку в case.

Сначала объявим enum:

import Foundation

enum Command {
    case help
    case list
    case exit
    case unknown
}

Теперь сделаем функцию, которая получает строку и решает, что это за команда:

import Foundation

enum Command { case help, list, exit, unknown }

func parseCommand(_ text: String) -> Command {
    switch text {
    case "help": return .help
    case "list": return .list
    case "exit": return .exit
    default:     return .unknown
    }
}

И используем это в мини-цикле:

import Foundation

enum Command { case help, list, exit, unknown }

let input = "help"
let cmd = parseCommand(input)

print(cmd) // help

Здесь unknown — это наш способ сохранить факт «непонятная команда» как легальный вариант состояния. Не идеальный, но на раннем этапе обучения — честный и понятный.

Чтобы увидеть процесс целиком, вот маленькая схема (она полезна, когда начинаете проектировать CLI):

flowchart TD
    A["Строка от пользователя (readLine)"] --> B["parseCommand(text)"]
    B --> C["Command enum"]
    C --> D["switch cmd { ... }"]
    D --> E["Действие программы (help/list/exit)"]

Когда вы используете enum, вы переносите часть ответственности с «памяти программиста» на компилятор. Раньше нужно было помнить, какие строки допустимы, и следить, чтобы они совпадали везде. Теперь компилятор знает, сколько вариантов существует, и не даст вам «случайно придумать новый».

Ещё один важный эффект: enum отлично работает в паре с switch. Когда вы начнёте писать switch по enum (подробно будет в следующих лекциях), Swift будет подталкивать вас к исчерпывающей обработке вариантов. В целом философия языка такая: «лучше поймать ошибку при компиляции, чем пользователю поймать её в проде».

А leading dot синтаксис (.caseName) — это часть того же подхода: сделать код короче, но только там, где он остаётся однозначным. Это подчёркивает мысль «это case, а не произвольное слово».

5. Типичные ошибки при использовании enum и cases

Ошибка №1: продолжать хранить режимы как String, потому что «так проще».
Обычно это происходит из лучших побуждений: хочется быстрее увидеть результат. Но затем в коде появляются проверки "Exit", "exit", "EXIT", и вы внезапно изобрели три разные команды, сами того не планируя. enum решает эту проблему в корне: вариантов конечное число, и вы обязаны выбрать один из них.

Ошибка №2: писать .someCase без контекста типа и не понимать, почему компилятор ругается.
Leading dot синтаксис работает только тогда, когда компилятор уже знает, какой тип ожидается. Если вы пишете let x = .admin, то тип неизвестен, и Swift не должен угадывать. Лечение простое: либо указывать тип переменной (let x: UserRole = .admin), либо писать полное имя (UserRole.admin).

Ошибка №3: путать разные enum, у которых совпадают имена cases.
Например, у вас есть UserRole.admin и ещё где-то AccessLevel.admin. Если типы разные, то и смысл может быть разный. Обычно проблема проявляется, когда вы держите переменные «где-то рядом» и начинаете копировать код. Спасает привычка смотреть на тип переменной и не злоупотреблять слишком общими именами.

Ошибка №4: превращать enum в «контейнер для всего на свете» уже на первом шаге.
Иногда хочется сразу засунуть в enum и команды, и аргументы, и ошибки, и состояния, и настроение кота в офисе. На раннем этапе обучения лучше держать enum простым: фиксированный набор вариантов. Мы ещё дойдём до более мощных вариантов, но сейчас важнее почувствовать, как enum дисциплинирует код, а не усложняет его.

1
Задача
Swift SELF, 25 уровень, 0 лекция
Недоступна
Статус посылки
Статус посылки
1
Задача
Swift SELF, 25 уровень, 0 лекция
Недоступна
Компас робота
Компас робота
1
Задача
Swift SELF, 25 уровень, 0 лекция
Недоступна
Команда терминала
Команда терминала
1
Задача
Swift SELF, 25 уровень, 0 лекция
Недоступна
Темы друзей
Темы друзей
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ