Перечисление (enumeration) определяет общий тип для группы связанных значений. Причем сами объединенные в перечисление значения могут представлять любой тип - число, строку и так далее.
Для создания перечисления используется ключевое слово enum:
enum Season{ case Winter case Spring case Summer case Autumn }
Каждое отдельное значение в перечислении указывается после оператора case. В данном случае перечисление называется Season и представляет времена года и имеет четыре значения. То есть фактически Season представляет новый тип данных.
Также допустима сокращенная форма перечисления значений:
enum Season{ case Winter, Spring, Summer, Autumn }
После определения перечисления мы сможем его использовать в программе:
var currentSeason = Season.Spring
Здесь переменная currentSeason
представляет тип Season
. Впоследствии мы можем присвоить этой переменной другое значение из
Season:
var currentSeason = .Summer
Либо мы можем сначала определить переменную / константу типа перечисления, а потом ее инициализировать:
let lastSeason: Season lastSeason = Season.Winter
С помощью конструкции switch
можно узнать, какое значение содержит переменная / константа, представляющая перечисление:
enum Season{ case Winter, Spring, Summer, Autumn } let currentSeason = Season.Spring switch(currentSeason){ case .Winter: print("Зима") case .Spring: print("Весна") case .Summer: print("Лето") case .Autumn: print("Осень") }
С каждым значением в перечислении мы можем ассоциировать какое-либо другое значения, которое может представлять любой тип. При этом ассоциированные значения для разных значений одного и того же перечисления могут представлять различные типы.
Итак, пусть у нас перечисление представляет игрового персонажа:
enum Person{ case Human(String, Int) case Elf(String) }
Здесь перечисление определяет два возможных значения - двух игровых персонажей: человека (Human) и эльфа (Elf). Однако у человека мы можем задать два парамета: имя (String) и количество жизней (Int). А у эльфа нам нужен только один параметр - имя (String).
То есть в данном случае значение Person.Human будет ассоциировано с двумя значениями String и Int, а значение Person.Elf - с одним значением типа String:
var hero = Person.Human("Trogvar", 5) hero = Person.Elf("Feonor")
С помощью конструкции switch мы также можем определить значение объекта:
switch(hero){ case .Human: print("Вы играете человеком") case .Elf: print("Вы играете эльфом") case .Gnom: print("Вы играете гномом") }
Но при необходимости мы также можем получить ассоциированные значения:
switch(hero){ case .Human (let name, let lives): print("Вы играете человеком. Имя: \(name), количество жизней: \(lives)") case .Elf (let name): print("Вы играете эльфом. Имя: \(name)") case .Gnom: print("Вы играете гномом") }
Для получения значений мы можем определить константы или переменные, в которые будут передаваться ассоциированные значения.
Кроме ассоциированных значений члены перечисления могут иметь чистые значения (raw values). Например, пусть у нас есть перечисление, представляющее флагманы различных производителей:
enum Flagman: String{ case Samsung = "Galaxy S9" case Apple = "iPhone X" case Microsoft = "Lumia 950" case Google = "Pixel 2" }
При определении чистых значений нам надо указать их тип. В данном случае типом будет выступать тип String. Затем в программе мы сможем получить эти чистые значения с помощью свойства rawValue:
var myPhone = Flagman.Apple print(myPhone) // Apple print(myPhone.rawValue) // iPhone X
Если мы укажем тип прямых значений, но не укажем эти самые значения, то swift использует значения по умолчанию.
Если тип - String, то чистые значения будут представлять строковое представление элементов перечисления:
enum Flagman: String{ case Samsung, Apple, Microsoft, Google } var myPhone = Flagman.Apple print(myPhone) // Apple print(myPhone.rawValue) // Apple
Фактически будет совпадение между значениями перечисления и их чистыми значениями.
Если типом для чистых значений является тип Int, то элементы перечисления получат значения по порядку:
enum DayOfWeek: Int{ case Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } var currentDay = DayOfWeek.Wednesday print(currentDay) // Wednesday print(currentDay.rawValue) // 3
Первый элемент перечисления Monday=1
задает начальное значение для элементов перечисления. Если же мы не укажем его, то начальным значением будет 0.
Используя чистое значение, мы можем получить элемент перечисления:
enum DayOfWeek: Int{ case Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } var currentDay = DayOfWeek(rawValue: 7) // Optional(DayOfWeek.Sunday) print(currentDay!)
В данном случае мы пытаемся получить элемент перечисления, который имеет чистое значение 7. Но данная операция возвращает не просто элемент перечисления, а объект Optional, то есть такой объект, который может иметь конкретное значение, а может иметь значение nil (отсутствие значения).
И если мы попытаемся получить, например, элемент с чистым значением 8, то мы получим nil. Поэтому мы можем применять условное выражение if для проверки полученного значения перед его использованием:
if let day = DayOfWeek(rawValue: 8){ print(day) }
Как классы и структуры, перечисления могут определять методы. Например:
enum DayOfWeek: Int{ case Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday func getCurrentDay() -> String{ return DayOfWeek.getDay(number: rawValue) } static func getDay(number: Int) -> String{ switch number{ case 1: return "Понедельник" case 2: return "Вторник" case 3: return "Среда" case 4: return "Четверг" case 5: return "Пятница" case 6: return "Суббота" case 7: return "Воскресенье" default: return "undefined" } } } var someDay: DayOfWeek = DayOfWeek.Sunday someDay.getCurrentDay() // Воскресенье var secondDay = DayOfWeek.getDay(number: 2) // Вторник
Перечисления также могут иметь свойства, но это не могут быть хранимые свойства. А вычисляемые свойства вполне будут работать:
enum DayOfWeek: Int{ case Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday var label : String { switch self { case .Monday: return "Понедельник" case .Tuesday: return "Вторник" case .Wednesday: return "Среда" case .Thursday: return "Четверг" case .Friday: return "Пятница" case .Saturday: return "Суббота" case .Sunday: return "Воскресенье" } } } let day1 = DayOfWeek.Monday print(day1.label) // Понедельник print(DayOfWeek.Friday.label) // Пятница
В данном случае свойство label автоматически вычисляется на основании значения текущего объекта перечисления. Текущий объект перечисления можно получить с помощью ключевого слова self.
И также перечисления могут иметь иниицализаторы:
enum DayOfWeek: Int{ case Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday init?(_ val:String) { switch val { case "Понедельник" : self = .Monday case "Вторник": self = .Tuesday case "Среда": self = .Wednesday case "Четверг": self = .Thursday case "Пятница": self = .Friday case "Суббота": self = .Saturday case "Воскресенье": self = .Sunday case _ : return nil } } } let day1 = DayOfWeek("Пятница") print(day1!.rawValue) // 5
В данном случае инициализатор принимает название дня недели и на его основании устанавливает значение текущего объекта. Если переданное название не распознано, то инициализатор возвращает nil.