Документация

Добавление реализации протокола через расширение

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

Заметка

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

К примеру, этот протокол TextRepresentable может быть реализован любым типом, который может отображать текст. Это может быть собственное описание или текстовая версия текущего состояния:

protocol TextRepresentable {
    func textualDescription() -> String
}

Класс Dice, о котором мы говорили ранее, может быть расширен для принятия и соответствия протоколу TextRepresentable:

extension Dice: TextRepresentable {
    func textualDescription() -> String {
        return "Игральная кость с \(sides) гранями"
    }
}

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

Теперь экземпляр Dice может быть использован как TextRepresetable:

let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription())
// Выведет "Игральная кость с 12 гранями"

Аналогично игровой класс SnakesAndLadders может быть расширен для того, чтобы смог принять и соответствовать протоколу TextRepresentable:

extension SnakesAndLadders: TextRepresentable {
    func textualDescription() -> String {
        return "Игра Змеи и Лестницы с полем в \(finalSquare) клеток"
    }
}
print(textualDescription())
// Выведет "Игра Змеи и Лестницы с полем в 25 клеток"

Условное соответствие протоколу

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

Следующее расширение делает экземпляры Array совместимыми с TextRepresentable протоколом всякий раз, когда они хранят элементы типа, которые соответствуют TextRepresentable:

extension Array: TextRepresentable where Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}
let myDice = [d6, d12]
print(myDice.textualDescription)
// Prints "[A 6-sided dice, A 12-sided dice]"

Принятие протокола через расширение

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

struct Hamster {
    var name: String
    func textualDescription() -> String {
        return "Хомяка назвали \(name)"
    }
}
extension Hamster: TextRepresentable {}

Экземпляры Hamster теперь могут быть использованы в тех случаях, когда нужен тип TextRepresentable:

let simonTheHamster = Hamster(name: "Фруша")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription())
// Выведет "Хомяка назвали Фруша"

Заметка

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

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: