Перечисления

Последнее обновление: 02.01.2018

Перечисление (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.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850