Что изменится при объявлении функции в протоколе Swift
Что проверяют
Понимаете ли вы, что перенос функции в объявление протокола меняет способ диспетчеризации. Это один из немногих вопросов, где ошибка приводит не к некрасивому коду, а к вызову не той реализации, поэтому его любят задавать на позициях выше начальных.
Как отвечать
Функция, объявленная в самом протоколе, становится его требованием: вызов идёт через таблицу соответствия, и для переменной типа протокола выполнится реализация конкретного типа. Функция, которая живёт только в расширении протокола и требованием не объявлена, диспетчеризуется статически, по типу переменной:
protocol Greeter {
func hello() // требование
}
extension Greeter {
func hello() { print("из протокола") } // значение по умолчанию
func bye() { print("из протокола") } // только в расширении
}
struct Person: Greeter {
func hello() { print("из типа") }
func bye() { print("из типа") }
}
let g: Greeter = Person()
g.hello() // из типа
g.bye() // из протоколаДобавьте остальные следствия. Требование обязательно для всех соответствующих типов, и добавление функции в протокол ломает сборку везде, пока нет реализации по умолчанию в расширении. Для структур и перечислений метод, меняющий состояние, объявляется с mutating. Требования с associatedtype или с Self делают протокол пригодным только как ограничение, отсюда some и any. Необязательные методы существуют лишь у протоколов, помеченных @objc, и только для классов.
Где спотыкаются
Не знают про разницу диспетчеризации и уверены, что вызовется реализация типа. Пример с bye из расширения ставит в тупик чаще всего, а в жизни это выглядит как метод, который «не переопределяется».
Считают реализацию в расширении переопределяемой как у класса. Слова override для такого случая нет, тип не переопределяет функцию, а прячет её, и поведение зависит от того, как объявлена переменная.
Обещают необязательные требования без @objc. Такой код не соберётся, а привязка к рантайму Objective-C закрывает дорогу структурам. Обычный способ сделать требование необязательным это реализация по умолчанию в расширении.