Поиск…


замечания

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

Дополнительные сведения о перечислениях см. В разделе «Быстрый язык программирования» .

Основные перечисления

Перечисление предоставляет набор связанных значений:

enum Direction {
    case up
    case down
    case left
    case right
}

enum Direction { case up, down, left, right }

Значения Enum могут использоваться их полностью квалифицированным именем, но вы можете опустить имя типа, когда это можно сделать:

let dir = Direction.up
let dir: Direction = Direction.up
let dir: Direction = .up

// func move(dir: Direction)...
move(Direction.up)
move(.up)

obj.dir = Direction.up
obj.dir = .up

Самый фундаментальный способ сравнения / извлечения значений enum - с помощью оператора switch :

switch dir {
case .up:
    // handle the up case
case .down:
    // handle the down case
case .left:
    // handle the left case
case .right:
    // handle the right case
}

Простые перечисления автоматически Hashable , Equatable и имеют преобразования строк:

if dir == .down { ... }

let dirs: Set<Direction> = [.right, .left]

print(Direction.up)  // prints "up"
debugPrint(Direction.up)  // prints "Direction.up"

Перечисления со связанными значениями

События Enum могут содержать одну или несколько полезных нагрузок ( связанных значений ):

enum Action {
    case jump
    case kick
    case move(distance: Float)  // The "move" case has an associated distance
}

Полезная нагрузка должна быть предоставлена ​​при создании экземпляра значения перечисления:

performAction(.jump)
performAction(.kick)
performAction(.move(distance: 3.3))
performAction(.move(distance: 0.5))

Оператор switch может извлечь связанное значение:

switch action {
case .jump:
    ...
case .kick:
    ...
case .move(let distance):  // or case let .move(distance):
    print("Moving: \(distance)") 
}

Выделение одного случая может быть выполнено с использованием if case :

if case .move(let distance) = action {
    print("Moving: \(distance)") 
}

Синтаксис guard case можно использовать для последующего использования:

guard case .move(let distance) = action else {
    print("Action is not move")
    return
}

Перечисления со связанными значениями по умолчанию не Equatable . Реализация оператора == должна выполняться вручную:

extension Action: Equatable { }

func ==(lhs: Action, rhs: Action) -> Bool {
    switch lhs {
    case .jump: if case .jump = rhs { return true }
    case .kick: if case .kick = rhs { return true }
    case .move(let lhsDistance): if case .move (let rhsDistance) = rhs { return lhsDistance == rhsDistance }
    }
    return false
}

Косвенная полезная нагрузка

Обычно перечисления не могут быть рекурсивными (потому что они потребуют бесконечного хранения):

enum Tree<T> {
    case leaf(T)
    case branch(Tree<T>, Tree<T>)  // error: recursive enum 'Tree<T>' is not marked 'indirect'
}

indirect ключевое слово заставляет enum хранить свою полезную нагрузку со слоем косвенности, а не хранить его в строке. Вы можете использовать это ключевое слово в одном случае:

enum Tree<T> {
    case leaf(T)
    indirect case branch(Tree<T>, Tree<T>)
}

let tree = Tree.branch(.leaf(1), .branch(.leaf(2), .leaf(3)))

indirect также работает на всей переписке, делая при необходимости косвенным косвенным образом:

indirect enum Tree<T> {
    case leaf(T)
    case branch(Tree<T>, Tree<T>)
}

Значения Raw и Hash

Перечисления без полезных нагрузок могут иметь необработанные значения любого литерального типа:

enum Rotation: Int {
    case up = 0
    case left = 90
    case upsideDown = 180
    case right = 270
}

Перечисления без определенного типа не выставляют свойство rawValue

enum Rotation {
    case up
    case right
    case down
    case left
}

let foo = Rotation.up
foo.rawValue //error

Предполагается, что значения целых сырых значений начинаются с 0 и монотонно возрастают:

enum MetasyntacticVariable: Int {
    case foo  // rawValue is automatically 0
    case bar  // rawValue is automatically 1
    case baz = 7
    case quux  // rawValue is automatically 8
}

Строковые исходные значения могут быть синтезированы автоматически:

enum MarsMoon: String {
    case phobos  // rawValue is automatically "phobos"
    case deimos  // rawValue is automatically "deimos"
}

Необработанное перечисление автоматически соответствует RawRepresentable . Вы можете получить соответствующее исходное значение значения .rawValue с помощью .rawValue :

func rotate(rotation: Rotation) {
    let degrees = rotation.rawValue
    ...
}

Вы также можете создать перечисление из необработанного значения с помощью init?(rawValue:) :

let rotation = Rotation(rawValue: 0)  // returns Rotation.Up
let otherRotation = Rotation(rawValue: 45)  // returns nil (there is no Rotation with rawValue 45)

if let moon = MarsMoon(rawValue: str) {
    print("Mars has a moon named \(str)")
} else {
    print("Mars doesn't have a moon named \(str)")
}

Если вы хотите получить хеш-значение определенного перечисления, вы можете получить доступ к его hashValue, хеш-значение вернет индекс перечисления, начиная с нуля.

let quux = MetasyntacticVariable(rawValue: 8)// rawValue is 8
quux?.hashValue //hashValue is 3

Инициализаторы

В Enums могут быть настраиваемые методы init, которые могут быть более полезными, чем init?(rawValue:) по умолчанию init?(rawValue:) . Enums также может хранить значения. Это может быть полезно для хранения значений, которые они инициализировали и извлекали это значение позже.

enum CompassDirection {
    case north(Int)
    case south(Int)
    case east(Int)
    case west(Int)

    init?(degrees: Int) {
        switch degrees {
        case 0...45:
            self = .north(degrees)
        case 46...135:
            self = .east(degrees)
        case 136...225:
            self = .south(degrees)
        case 226...315:
            self = .west(degrees)
        case 316...360:
            self = .north(degrees)
        default:
            return nil
        }
    }
    
    var value: Int = {
        switch self {
            case north(let degrees):
                return degrees
            case south(let degrees):
                return degrees
            case east(let degrees):
                return degrees
            case west(let degrees):
                return degrees
        }    
    }
}

Используя этот инициализатор, мы можем сделать это:

var direction = CompassDirection(degrees: 0) // Returns CompassDirection.north
direction = CompassDirection(degrees: 90) // Returns CompassDirection.east
print(direction.value) //prints 90
direction = CompassDirection(degrees: 500) // Returns nil

Перечисления разделяют многие функции с классами и структурами

Перечисления в Swift намного мощнее, чем некоторые из их коллег на других языках, таких как C. Они имеют множество функций с классами и структурами , такими как определение инициализаторов , вычисляемых свойств , методов экземпляров , соответствия протоколов и расширений .

protocol ChangesDirection {
    mutating func changeDirection()
}

enum Direction {
    
    // enumeration cases
    case up, down, left, right
    
    // initialise the enum instance with a case
    // that's in the opposite direction to another
    init(oppositeTo otherDirection: Direction) {
        self = otherDirection.opposite
    }
    
    // computed property that returns the opposite direction
    var opposite: Direction {
        switch self {
        case .up:
            return .down
        case .down:
            return .up
        case .left:
            return .right
        case .right:
            return .left
        }
    }
}

// extension to Direction that adds conformance to the ChangesDirection protocol
extension Direction: ChangesDirection {
    mutating func changeDirection() {
        self = .left
    }
}

var dir = Direction(oppositeTo: .down) // Direction.up

dir.changeDirection() // Direction.left

let opposite = dir.opposite // Direction.right

Вложенные перечисления

Вы можете встраивать перечисления один внутри другого, это позволяет вам структурировать иерархические перечисления, чтобы быть более организованными и понятными.

enum Orchestra {
    enum Strings {
        case violin
        case viola
        case cello
        case doubleBasse
    }
    
    enum Keyboards {
        case piano
        case celesta
        case harp
    }
    
    enum Woodwinds {
        case flute
        case oboe
        case clarinet
        case bassoon
        case contrabassoon
    }
}

И вы можете использовать его так:

let instrment1 = Orchestra.Strings.viola
let instrment2 = Orchestra.Keyboards.piano


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow