Enumerated swift что это
Перейти к содержимому

Enumerated swift что это

  • автор:

Enumerated swift что это

Перечисление (enumeration) определяет общий тип для группы связанных значений. Причем сами объединенные в перечисление значения могут представлять любой тип — число, строку и так далее.

Для создания перечисления используется ключевое слово enum :

enum Season

Каждое отдельное значение в перечислении указывается после оператора case . В данном случае перечисление называется Season и представляет времена года и имеет четыре значения. То есть фактически Season представляет новый тип данных.

Также допустима сокращенная форма перечисления значений:

enum Season

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

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)

Ассоциированные значения

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

Итак, пусть у нас перечисление представляет игрового персонажа:

enum Person

Здесь перечисление определяет два возможных значения — двух игровых персонажей: человека (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)

Но при необходимости мы также можем получить ассоциированные значения:

switch(hero)

Для получения значений мы можем определить константы или переменные, в которые будут передаваться ассоциированные значения.

Чистые значения перечислений

Кроме ассоциированных значений члены перечисления могут иметь чистые значения (raw values). Например, пусть у нас есть перечисление, представляющее флагманы различных производителей:

enum Flagman: String

При определении чистых значений нам надо указать их тип. В данном случае типом будет выступать тип 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)

Методы перечислений

Как классы и структуры, перечисления могут определять методы. Например:

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.

Перечисления (enum) в Swift: ассоциированные и чистые значения

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

Хорошим примером являются направления на компасе:

enum Compass  case north case east case south case west >

Перечисления помогают нам работать со связанными значениями наиболее безопасным способом.

Проще всего рассматривать перечисления как структурированные списки связанных элементов. К примеру:

  • Цвета: красный, зеленый, синий, фиолетовый, желтый.
  • Вкусы мороженого: ваниль, шоколад, клубника.
  • Состояния аутентификации: .authenticated, .unauthenticated, .undetermined.
  • Состояния воспроизведения: .playing, .paused, .stoppped.

Синтаксис перечислений довольно прост:

  • Мы используем ключевое слово enum для объявления перечисления с используем конструкцию enum имя < тело >.
  • В теле перечислений мы включаем ряд элементов перечисления с помощью ключевого слова case. Варианты перечисления – это разные значения, которые у него есть, например, вышеупомянутые ароматы мороженого.
  • Перечисления могут иметь ассоциированные значения (associated types), а также чистые значения (raw value).

Мы можем определить все перечисления в одной строке:

case Weekday  case monday, tuesday, wednesday, thursday, friday, saturday, sunday >

Использовать перечисление довольно просто:

let today: Weekday = Weekday.monday

Приведенный выше код можно сократить:

let today: Weekday = .monday

Также можно использовать:

let today = Weekday.monday

Благодаря выводу типа нам не нужно каждый раз явно объявлять тип переменной или константы. Как только тип перечисления был объявлен, мы можем использовать более короткий синтаксис:

var direction: Compass = .north direction = .south

Перечисления нельзя изменить после установки.

enum AuthenticationState  case authenticated case unauthenticated case undetermined >

Значения перечисления являются исчерпывающими, и вы можете быть уверены, что любое значение типа AuthenticationState является любым из трех значений. Это обеспечивает безопасность в вашем коде и приводит к меньшему количеству ошибок.

Перечисления, состояния и switch

Перечисления эффективно комбинировать с оператором switch. Возможно, вы слышали о понятии «состояние» раньше. В разработке для iOS мы часто управляем состоянием различных параметров и взаимодействий в нашем приложении.

Представьте, что мы кодируем робота. У робота есть эмоции. Мы моделируем эти эмоции или состояния с помощью перечисления:

enum Emotion  case happy, sad, angry, scared, surprised >

Теперь мы можем использовать оператор switch, чтобы реагировать на эти эмоции:

switch robot.mood  case .angry: robot.destroyAllHumans() case .sad: robot.rust() // Робот плачет и ржавеет. case .happy: robot.play("happy.mp3") case default: print("Неизвестная эмоция.") >

Каждый case в блоке switch соответствует отдельному case в перечислении.

Ассоциированные значения (associated values) в перечислениях

Перечисления позволяют вам присвоить одно из предопределенных значений переменной или константе. Также мы можем связать значения с отдельными случаями перечисления.

Представьте, что мы создаем приложение для ролевой игры (RPG). Игрок может добавить в свой инвентарь несколько типов предметов. Каждый предмет имеет разные свойства. Например:

  • У оружия есть очки урона и вес.
  • У еды есть очки здоровья.
  • У брони есть очки защиты, вес и состояние.

Вот как это выглядит с ассоциированными значениями:

enum Item  case weapon(Int, Int) case food(Int) case armor(Int, Int, Double) > var sword = Item.weapon(10, 5)

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

Далее мы можем написать функцию для использования определенного предмета из инвентаря игрока:

func use(item: Item)  switch item  case .weapon(let hitPoints, _): player.attack(hitPoints) case .food(let health): player.health += health case .armor(let damageThreshold, let weight, let condition): player.damageThreshold = Double(damageThreshold) * condition > >

В приведенном выше коде мы разбиваем значения кортежей на отдельные константы. К примеру, константа hitPoints соответствует первому значению Int для case weapon(Int, Int).

Если вы хотите получить доступ ко всем ассоциированным значениям, вы можете использовать одиночный let:

switch item  case let .armor(damageThreshold, weight, condition): player.damageThreshold = ··· >

Вы также можете сопоставлять ассоциированные значения:

let item = Item.armor(15, 10, 0.75) switch item  case let .armor(damageThreshold, weight, condition) where weight  10: print("DT = \(Double(damageThreshold) * condition)") case .armor: print("Броня слишком тяжелая!") default: print("Это не броня.") > // Броня слишком тяжелая!

В приведенном выше коде мы используем ключевое слово where для сопоставления .armor случаев, когда weight меньше 10. Во втором случае мы сопоставляем любой .armor случай, который не соответствует первому, то есть любой, для которого weight больше или равен 10.

В Swift часто встречаются перечисления с ассоциированными значениями. Возьмем, к примеру, перечисление Result для Alamofire, популярной сетевой библиотеки.

public enum ResultValue>  case success(Value) case failure(Error) ··· public var value: Value?  switch self  case .success(let value): return value case .failure: return nil > > >

В перечислении Result используется дженерик Value и протокол Error для представления двух возможных состояний: результат успешного или неудачного запроса. Когда запрос выполнен успешно, мы можем получить Value, а когда он потерпел неудачу, мы можем получить Error.

Вычисляемое свойство value перечисления Result возвращает опциональное значение Value?. Мы используем оператор switch для возврата значения или nil.

Использование чистых значений (raw values) для перечислений

Вместо связанных значений перечисления могут иметь чистые значения:

enum Flavor: String  case vanilla = "vanilla" case strawberry = "strawberry" case chocolate = "chocolate" >

Каждый случай перечисления Flavor использует значения типа String.

Посмотрим, как можно работать с чистыми значениями:

let icecream = Flavor.vanilla print(icecream.rawValue) // vanilla

Мы также можем получить значение Flavor прямо из чистого значения. При этом инициализатор чистого значения возвращает опциональный параметр:

let icecream = Flavor(rawValue: "vanilla") print(icecream) // Optional(Flavor.vanilla)

Чистые значения также могут назначаться неявно:

enum Weekday: Int  case monday = 1, tuesday, wednesday, thursday, friday, saturday, sunday >

В приведенном выше примере исходное значение .sunday равно 7.

Для значений типа String это работает аналогично. Чистые значения будут представлять собой строковые значения элементов перечисления:

enum Compass: String  case north, east, south, west > let direction = Compass.west print(direction.rawValue == "west") // true

Перечисления (enumeration) в Swift

Перечисление — это объектный тип данных, который предоставляет доступ к различным предопределенным значениям. Рассматривайте его как перечень возможных значений, то есть набор констант, значения которых являются альтернативами друг другу.

Задание 1

1) В конце главы про «Перечисления» мы с вами начали создавать перечисление ArithmeticExpression, позволяющее выполнять арифметические операции. Сейчас перед вами стоит задача доработать данное перечисление, чтобы оно могло производить любые арифметические операции, включая сложение, вычитание, умножение, деление и возведение в степень.
2) Проверьте работу перечисления на произвольных примерах

Правильный ответ

enum ArithmeticExpression < // указатель на конкретное значение case number( Int ) // указатель на операцию сложения indirect case addition( ArithmeticExpression, ArithmeticExpression ) // указатель на операцию вычитания indirect case subtraction( ArithmeticExpression, ArithmeticExpression ) // указатель на операцию умножения indirect case multiplaction( ArithmeticExpression, ArithmeticExpression ) // указатель на операцию деления indirect case division( ArithmeticExpression, ArithmeticExpression ) // указатель на операцию возведения в степень indirect case pow( ArithmeticExpression, ArithmeticExpression ) // метод, проводящий операцию func evaluate( _ expression: ArithmeticExpression? = nil ) ->Int< // определение типа операнда (значение или операция) switch expression ?? self< case let .number( value ): return value case let .addition( valueLeft, valueRight ): return self.evaluate( valueLeft )+self.evaluate( valueRight ) case .subtraction( let valueLeft, let valueRight ): return self.evaluate( valueLeft )-self.evaluate( valueRight ) case .multiplaction( let valueLeft, let valueRight ): return self.evaluate( valueLeft )*self.evaluate( valueRight ) case .division( let valueLeft, let valueRight ): return self.evaluate( valueLeft )/self.evaluate( valueRight ) case .pow( let valueLeft, let valueRight ): if self.evaluate( valueRight ) == 0 < return 1 >else < var result = self.evaluate( valueLeft ) for _ in 1..return result > > > > var hardExpr = ArithmeticExpression.pow( .number(3), .number(3) ) hardExpr.evaluate() // 27 hardExpr = ArithmeticExpression.multiplaction( .number(3), .number(3) ) hardExpr.evaluate() // 9

Задание 2

Корректно ли будет выполнен данный код? Если нет, то какие правки необходимо в него внести, чтобы исправить ошибки?

enum Seasons < case winter, spring, summer, autumn >let whiteSeason = Seasons.winter var greenSeason: Seasons = .spring greenSeason = .summer var orangeSeason = .autumn var bestSeason = whiteSeason bestSeason = .summer

Правильный ответ

Ошибка в строке 7. У переменной orangeSeason не указан тип данных

Доступ закрыт

Дополнительные 2 задания доступны только подписчикам

4 Comments

Задание 1: enum ArithmeticExpression <
// указатель на конкретное значение
case number( Int )
// указатель на операцию сложения
indirect case addition( ArithmeticExpression, ArithmeticExpression )
// указатель на операцию вычитания
indirect case subtraction( ArithmeticExpression, ArithmeticExpression )
// метод, проводящий операцию умножения
indirect case multiplication( ArithmeticExpression, ArithmeticExpression )
// метод, проводящий операцию деления
indirect case division( ArithmeticExpression, ArithmeticExpression )
// метод, проводящий операцию возведения в корень
indirect case pow1( ArithmeticExpression, ArithmeticExpression )
// метод, проводящий операцию
func evaluate( _ expression: ArithmeticExpression? = nil ) -> Int <
// определение типа операнда (значение или операция)
switch expression ?? self <
case let .number( value ):
return value
case let .addition( valueLeft, valueRight ):
return self.evaluate( valueLeft ) + self.evaluate ( valueRight )
case .subtraction( let valueLeft, let valueRight ):
return self.evaluate( valueLeft ) — self.evaluate ( valueRight )
case .multiplication( let valueLeft, let valueRight ):
return self.evaluate( valueLeft ) * self.evaluate ( valueRight )
case .division( let valueLeft, let valueRight ):
return self.evaluate( valueLeft ) / self.evaluate ( valueRight )
case .pow1( let valueLeft, let valueRight ):
return Int (pow (Double (self.evaluate ( valueLeft )), Double (self.evaluate ( valueRight ))))
>
>
>
var hardExpr = ArithmeticExpression.addition( .number(20), .division( .number(10), .number(5) ) )
hardExpr.evaluate() // 22 var hardExpr1 = ArithmeticExpression.pow1( .number(10), .number(2) )
hardExpr1.evaluate() // 100

Согласен с Vlados. И в ответе на Задание 1 — в for in в теле функции должно стоять result *= self.evalute(valueLeft), что бы перемножал определенное количество раз self.evalute(valueRight) на число, которое должно ВОЗВОВОДИТЬСЯ в степень self.evalute(valueLeft). А в ответе получается наоборот.

enum Day: String <
case monday = «Понедельник»
case tuesday = «Вторник»
case wednesday = «Среда»
case thursday = «Четверг»
case friday = «Пятница»
case saturday = «Суббота»
case sunday = «Воскресенье»
var label: String
>

Добавить комментарий Отменить ответ

Для отправки комментария вам необходимо авторизоваться.

Enum в Swift: Перечисления Возможных Сценариев

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

Начнем с самого простого, для создания перечисления мы используем ключевое слово enum:

enum DayOfWeek

Это определяет перечисление DayOfWeek , которое может принимать одно из значений: sunday , monday , tuesday и т.д

let currentDay = DayOfWeek.sunday 

Поскольку набор определенных значений в перечислении конечен очень распространено использование оператора switch для перебора значений вместо использования нескольких операторов if else:

switch currentDay

Associated Values

Однако иногда нам может потребоваться хранить дополнительные данные для каждого случая перечисления. Эта дополнительная информация, прикрепленная к значениям перечисления, называется связанными значениями (Associated Values).

Давайте рассмотрим подробный пример, используя перечисление Result , которое представляет результат выполнения операции с ассоциированными значениями для успешного результата или ошибки:

enum Result

В этом примере, Result имеет два случая:

  1. .success(T) : представляет успешный результат операции и ассоциированное значение типа T
  2. .failure(String) : представляет ошибку и ассоциированное текстовое сообщение об ошибке

Теперь создадим функцию, которая выполняет деление двух чисел и возвращает Result с результатом или ошибкой:

func divide(_ dividend: Double, by divisor: Double) -> Result  < if divisor == 0 < return .failure("Division by zero is not allowed.") >let result = dividend / divisor return .success(result) > 

Теперь мы можем использовать эту функцию для выполнения деления и обработки результата с использованием ассоциированных значений:

let result1 = divide(10, by: 2) switch result1 < case .success(let value): print("Результат: \(value)") case .failure(let error): print("Ошибка: \(error)") >let result2 = divide(5, by: 0) switch result2

В первом случае result1 будет .success(5.0) , и мы получим «Результат: 5.0«. Во втором случае result2 будет .failure(«Division by zero is not allowed.») , и мы получим «Ошибка: Делить на ноль нельзя«

Таким образом, ассоциированные значения в перечислениях позволяют передавать дополнительные данные в каждом случае перечисления, что полезно для представления различных сценариев и обработки ошибок.

Raw Values

Рассмотрим пример с перечислением, использующим сырые значения (raw values — могут быть строками, символами или числами). Возьмем перечисление HTTPStatus , которое представляет стандартные HTTP статусы, и свяжем каждый статус с его числовым кодом:

enum HTTPStatus: Int

Здесь каждый статус HTTP связан с числовым значением, которое соответствует его коду ответа.

Теперь мы можем использовать это перечисление для представления статусов HTTP в нашем коде:

let responseCode = 404 if let httpStatus = HTTPStatus(rawValue: responseCode) < switch httpStatus < case .ok: print("Success: 200 OK") case .notFound: print("Error: 404 Not Found") case .internalServerError: print("Error: 500 Internal Server Error") default: print("Received an HTTP status with code \(httpStatus.rawValue)") >> else

В этом примере мы получаем код ответа от сервера (404), затем создаем экземпляр перечисления HTTPStatus с использованием rawValue , и в конечном итоге, на основе значения, выполняем соответствующие действия. Это помогает нам легко работать с HTTP статусами и улучшает читаемость кода.

Продвинутые концепции

Ассоциированные значения с функциями

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

Рассмотрим подробный пример, используя перечисление Operation , которое представляет различные математические операции с ассоциированными функциями:

enum Action < case printMessage(() ->Void) case calculateSum((Int, Int) -> Int) > // Создадим экземпляры перечисления с ассоциированными функциями let printAction = Action.printMessage(< print("Hello, World!") >) let sumAction = Action.calculateSum(< a, b in return a + b >) // Выполним ассоциированные функции switch printAction < case .printMessage(let action): action() case .calculateSum(let action): // Этот случай не будет выполнен в данном примере break >switch sumAction < case .printMessage(let action): // Этот случай не будет выполнен в данном примере break case .calculateSum(let action): let result = action(5, 3) print("Result is: \(result)") >//Вывод: //Hello, World! //Result is: 8
  1. Мы создаем перечисление Action , где каждый случай перечисления имеет ассоциированную функцию
  2. Мы создаем экземпляры перечисления Action , привязывая к ним соответствующие функции
  3. Мы используем оператор switch , чтобы выполнить ассоциированные функции в зависимости от типа действия
  4. В первом switch мы выполняем функцию для printAction , которая печатает «Hello, World!»
  5. Во втором switch мы выполняем функцию для sumAction , которая выполняет сложение двух чисел (5 и 3) и печатает результат

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

Использование associatedtype с ассоциированными значениями

Использование associatedtype с ассоциированными значениями позволяет сделать перечисления в Swift более гибкими и адаптивными. Это особенно полезно, когда нам нужно, чтобы ассоциированные значения могли быть разных типов для разных случаев перечисления.

Предположим, у нас есть перечисление Shape , которое представляет разные геометрические фигуры, такие как круг, прямоугольник и треугольник. Мы хотим, чтобы каждая фигура имела разные ассоциированные значения, такие как радиус для круга, ширина и высота для прямоугольника и стороны для треугольника. Вот как это можно сделать с использованием associatedtype :

enum Shape

Теперь создадим протокол Drawable , который будет использовать associatedtype для определения ассоциированных значений для каждой фигуры:

protocol Drawable < associatedtype DrawingType func draw() ->DrawingType > 

Расширим перечисление Shape , чтобы оно соответствовало этому протоколу и определит ассоциированный тип DrawingType для каждой фигуры:

extension Shape: Drawable < typealias DrawingType = String func draw() ->DrawingType < switch self < case .circle(let radius): return "Рисуем круг с радиусом \(radius)" case .rectangle(let width, let height): return "Рисуем прямоугольник с шириной \(width) и высотой \(height)" case .triangle(let side1, let side2, let side3): return "Рисуем треугольник со сторонами \(side1), \(side2), \(side3)" >> > 

Теперь мы можем создавать экземпляры фигур и вызывать метод draw() , который возвращает строку, представляющую отрисовку фигуры:

let circle = Shape.circle(radius: 5.0) let rectangle = Shape.rectangle(width: 10.0, height: 8.0) let triangle = Shape.triangle(side1: 3.0, side2: 4.0, side3: 5.0) print(circle.draw()) // Вывод: Рисуем круг с радиусом 5.0 print(rectangle.draw()) // Вывод: Рисуем прямоугольник с шириной 10.0 и высотой 8.0 print(triangle.draw()) // Вывод: Рисуем треугольник со сторонами 3.0, 4.0, 5.0 

Рекурсивные перечисления

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

Рассмотрим подробнее, создадим рекурсивное перечисление для представления простых арифметических выражений. Выражения могут быть либо целыми числами, либо бинарными операциями (сложение или умножение) между двумя выражениями:

indirect enum ArithmeticExpression
  • ArithmeticExpression — это рекурсивное перечисление, которое может иметь три случая: .number , представляющий целое число, .addition , представляющий операцию сложения между двумя выражениями, и .multiplication , представляющий операцию умножения между двумя выражениями.
  • Ключевое слово indirect используется перед случаями .addition и .multiplication , чтобы указать, что эти случаи могут содержать рекурсивные значения (другие выражения).

Теперь мы можем создавать и вычислять арифметические выражения:

let expression = ArithmeticExpression.addition( .number(5), .multiplication( .number(2), .number(3) ) ) func evaluate(_ expression: ArithmeticExpression) -> Int < switch expression < case .number(let value): return value case .addition(let left, let right): return evaluate(left) + evaluate(right) case .multiplication(let left, let right): return evaluate(left) * evaluate(right) >> let result = evaluate(expression) print("Результат вычисления: \(result)") // Вывод: Результат вычисления: 11 

В этом примере мы создаем арифметическое выражение, которое представляет выражение 5 + (2 * 3) . Затем мы используем рекурсивную функцию evaluate , чтобы вычислить значение этого выражения.

Протоколы и перечисления

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

// Протокол Playable определяет объекты, которые можно воспроизводить protocol Playable < func play() >// Перечисление MediaType представляет различные типы медиафайлов enum MediaType < case audio(title: String, duration: TimeInterval) case video(title: String, duration: TimeInterval) case text(title: String, content: String) >// Реализация протокола Playable для перечисления MediaType extension MediaType: Playable < func play() < switch self < case .audio(let title, let duration): print("Воспроизведение аудио: \(title), Длительность: \(duration) секунд") case .video(let title, let duration): print("Воспроизведение видео: \(title), Длительность: \(duration) секунд") case .text(let title, let content): print("Отображение текста: \(title) - \(content)") >> > // Создаем медиафайлы с использованием перечисления MediaType let audioFile = MediaType.audio(title: "Music", duration: 180.0) let videoFile = MediaType.video(title: "Movie", duration: 1200.0) let textFile = MediaType.text(title: "Document", content: "Это образец документа") // Воспроизводим или отображаем медиафайлы audioFile.play() videoFile.play() textFile.play() 
  1. Мы создали протокол Playable , который определяет единственное требование — метод play() , предназначенный для воспроизведения объекта.
  2. Создано перечисление MediaType , которое представляет различные типы медиафайлов: аудио, видео и текст. Каждый случай перечисления имеет связанные значения для хранения информации о медиафайле.
  3. Расширение MediaType реализует протокол Playable , предоставляя метод play() , который выводит информацию о воспроизведении или отображении медиафайла.
  4. Мы создали разные медиафайлы, используя случаи перечисления MediaType .
  5. Вызвали метод play() для каждого медиафайла, демонстрируя, как протокол Playable позволяет воспроизводить или отображать разные типы медиафайлов с использованием единого интерфейса.

Пользовательские операторы

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

Оператор для сравнения приоритетов задач:

Допустим, у вас есть перечисление TaskPriority , которое представляет разные приоритеты задач:

enum TaskPriority

Вы можете добавить пользовательский оператор для сравнения приоритетов задач:

infix operator < func < (lhs: TaskPriority, rhs: TaskPriority) ->Bool < switch (lhs, rhs) < case (.low, .medium), (.low, .high), (.medium, .high): return true default: return false >> let lowPriority = TaskPriority.low let mediumPriority = TaskPriority.medium let highPriority = TaskPriority.high if lowPriority < mediumPriority < print("Low priority меньше чем Medium priority") >//Вывод: Low priority меньше чем Medium priority
Оператор для объединения имен файлов:

Предположим, у вас есть перечисление File , которое представляет файлы, и вы хотите объединить их имена с помощью оператора + :

enum File < case image(String) case document(String) >infix operator + func + (lhs: File, rhs: File) -> File < switch (lhs, rhs) < case let (.image(name1), .image(name2)): return .image(name1 + name2) case let (.document(name1), .document(name2)): return .document(name1 + name2) default: return .document("Invalid") >> let imageFile1 = File.image("image1.jpg") let imageFile2 = File.image("image2.jpg") let documentFile1 = File.document("document1.pdf") let combinedImageFiles = imageFile1 + imageFile2 let combinedDocumentFiles = documentFile1 + imageFile1 print("Combined Image Files: \(combinedImageFiles)") print("Combined Document Files: \(combinedDocumentFiles)") 

В этом примере мы определили пользовательский оператор + , который объединяет имена файлов из случаев File . Мы также проверяем типы файлов и возвращаем «Invalid» , если пытаемся объединить файлы разных типов.

Заключение:

Перечисления — ключевая часть языка, которая помогает в создании чистого, понятного и безопасного кода, они удивительно полезны при проектировании архитектуры приложения, создании API и обработке состояний, так что держим этот инструмент в своем арсенале и используем его с умом!

  • Программирование
  • Совершенный код
  • Разработка под iOS
  • Разработка мобильных приложений
  • Swift

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *