← Назад к вопросам

Какие знаешь виды Enum?

1.7 Middle🔥 211 комментариев
#Коллекции и структуры данных#Язык Swift

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Виды Enum в Swift

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

1. Базовые (Case) Enums

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

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

let direction: CompassDirection = .north
switch direction {
case .north:
    print("Heading north")
default:
    break
}

2. Enums с Raw Values (сырыми значениями)

Каждому кейсу предопределяется значение базового типа (String, Character, Int, Float). Для Int значения могут быть автоматически инкрементными, для String — равными имени кейса.

enum Planet: Int {
    case mercury = 1, venus, earth, mars // venus будет 2, earth — 3
}

enum HTTPStatus: String {
    case success = "200 OK"
    case notFound = "404 Not Found"
}

let earth = Planet.earth
print(earth.rawValue) // Вывод: 3

3. Enums с Associated Values (ассоциированными значениями)

Пожалуй, самая мощная особенность enum в Swift. Позволяет хранить дополнительные данные разного типа вместе с кейсом. Это ключевое отличие от raw values, где значение одно для всех экземпляров кейса.

enum Barcode {
    case upc(Int, Int, Int, Int) // Ассоциированные значения типа Int
    case qrCode(String)           // Ассоциированное значение типа String
}

let productCode = Barcode.upc(8, 85909, 51226, 3)

switch productCode {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let codeString):
    print("QR: \(codeString)")
}

Использование таких enum отлично подходит для моделирования вариантов результата (например, успех/ошибка с данными) или дискриминантных объединений.

4. Рекурсивные Enums (Indirect)

Позволяют кейсу иметь ассоциированное значение, которое является тем же типом enum. Требуют указания ключевого слова indirect — либо для всего enum, либо для конкретного кейса. Классический пример — моделирование арифметического выражения или связного списка.

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

let expr = ArithmeticExpression.addition(
    .number(5),
    .multiplication(.number(2), .number(3))
)

5. Enums с методами и вычисляемыми свойствами

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

enum TrafficLight {
    case red, yellow, green
    
    var description: String { // Вычисляемое свойство
        switch self {
        case .red: return "Stop"
        case .yellow: return "Wait"
        case .green: return "Go"
        }
    }
    
    mutating func next() { // Мутирующий метод
        switch self {
        case .red: self = .green
        case .yellow: self = .red
        case .green: self = .yellow
        }
    }
}

var light = TrafficLight.red
print(light.description) // "Stop"
light.next()
print(light) // green

6. Enums, соответствующие протоколам

Enum может соответствовать одному или нескольким протоколам, например, CaseIterable для автоматического получения массива всех кейсов, CustomStringConvertible для кастомного описания.

enum GameState: CaseIterable, Equatable {
    case menu, playing, paused, gameOver
}

for state in GameState.allCases {
    print(state)
}
// Будет выведено: menu, playing, paused, gameOver

Ключевые различия и когда что использовать:

  • Raw Values vs Associated Values: Используйте Raw Values, когда каждому кейсу нужно присвоить уникальное, предопределённое постоянное значение (статусы, коды). Используйте Associated Values, когда кейс должен нести различную дополнительную информацию, которая может меняться от экземпляра к экземпляру (сетевой ответ, событие UI).
  • CaseIterable: Незаменим для автоматической генерации списка всех кейсов, что полезно для тестов, UI-пикеров или конфигураций.
  • Рекурсивные enum: Специфичны, но идеальны для моделирования древовидных или иерархических структур данных прямо в системе типов.

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