.count }.reduce(0, +) return Int(round(Double(size) / Double(count.toIntMax()))) } }

Сега можем да изчислим средния размер на всяка колекция от опашки (Array, Set и т.н.). Без разширения на протокола, би трябвало да добавим този метод към всеки тип колекция поотделно.

В стандартната библиотека Swift се използват разширения на протокол, за да се внедрят например такива методи като map, filter, reduce и т.н.

верига на стойността на интернет на нещата
extension Collection { public func map(_ transform: (Self.Iterator.Element) throws -> T) rethrows -> [T] { } }

Разширения на протокола и полиморфизъм

Както казах по-рано, разширенията на протокола ни позволяват да добавим реализации по подразбиране на някои методи и да добавим и нови реализации на методи. Но каква е разликата между тези две характеристики? Да се ​​върнем към манипулатора на грешки и да разберем.

protocol ErrorHandler { func handle(error: Error) } extension ErrorHandler { func handle(error: Error) { print(error.localizedDescription) } } struct Handler: ErrorHandler { func handle(error: Error) { fatalError('Unexpected error occurred') } } enum ApplicationError: Error { case other } let handler: Handler = Handler() handler.handle(error: ApplicationError.other)

Резултатът е фатална грешка.

Сега премахнете handle(error: Error) декларация на метод от протокола.

protocol ErrorHandler { }

Резултатът е същият: фатална грешка.

Означава ли това, че няма разлика между добавяне на изпълнение по подразбиране на метода на протокола и добавяне на нов метод на изпълнение към протокола?

Не! Разлика съществува и можете да я видите, като промените типа на променливата handler от Handler до ErrorHandler.

let handler: ErrorHandler = Handler()

Сега изходът към конзолата е: Операцията не може да бъде завършена. (Грешка в ApplicationError 0.)

Но ако върнем метода на декларацията на манипулатора (грешка: грешка) към протокола, резултатът ще се промени обратно до фаталната грешка.

protocol ErrorHandler { func handle(error: Error) }

Нека разгледаме реда на това, което се случва във всеки отделен случай.

Когато декларацията за метод съществува в протокола:

Протоколът декларира handle(error: Error) метод и осигурява изпълнение по подразбиране. Методът е заменен в Handler изпълнение. Така че, правилното изпълнение на метода се извиква по време на изпълнение, независимо от типа на променливата.

Когато декларацията за метод не съществува в протокола:

Тъй като методът не е деклариран в протокола, типът не може да го замени. Ето защо изпълнението на извикан метод зависи от типа на променливата.

Ако променливата е от тип Handler, се извиква изпълнението на метода от типа. В случай, че променливата е от тип ErrorHandler, се извиква изпълнението на метода от разширението на протокола.

Протоколно ориентиран код: Безопасен, но изразителен

В тази статия демонстрирахме част от силата на разширенията на протокола в Swift.

За разлика от други езици за програмиране с интерфейси, Swift не ограничава протоколите с ненужни ограничения. Swift работи около често срещаните странности на тези програмни езици, като позволява на разработчика да разрешава неясноти, ако е необходимо.

С протоколите Swift и разширенията на протоколите кодът, който пишете, може да бъде толкова изразителен, колкото повечето динамични езици за програмиране, и въпреки това да бъде безопасен за типа по време на компилация. Това ви позволява да осигурите повторна употреба и поддръжка на вашия код и да правите промени в кодовата база на приложението Swift с повече увереност.

Надяваме се, че тази статия ще ви бъде полезна и ще приветстваме всякакви отзиви или по-нататъшна информация.