Реализована ли реализация быстрого расширения по умолчанию при компиляции или во время выполнения?
Мне интересно, есть ли способ работать с реализациями протокола по умолчанию в полиморфном стиле. пример
protocol RockInterface {
}
extension RockInterface {
func foo() {
print("You Rock")
}
}
extension RockInterface where Self: Metal {
func foo() {
print("Metal")
}
}
extension RockInterface where Self: Grunge {
func foo() {
print("Grunge")
}
}
class Rock: RockInterface {
init() {
foo()
}
}
class Metal: Rock {
}
class Grunge: Rock {
}
let rock = Rock() //prints "You Rock"
let metal = Metal() //prints "You Rock"
let grunge = Grunge() //prints "You Rock"
Я ожидал, что Metal() напечатает "Metal", а Grunge - "Grunge". Но кажется, что реализации по умолчанию решаются во время компиляции, а не во время выполнения. Мое предположение правильно неправильно? Как я мог получить ожидаемое поведение?
1 ответ
Есть как минимум два фактора, влияющих на поведение, которое вы видите, некоторые из которых находятся под вашим контролем, а некоторые нет.
- функции, которые не являются частью требований протокола, отправляются статически. Если вам нужна динамическая отправка, вам нужно добавить метод в объявление протокола:
protocol RockInterface {
func foo()
}
- однако приведенное выше не решит вашу проблему, поскольку подклассы наследуют таблицу-свидетель протокола родительского класса. Смотрите этот отличный ответ для более подробной информации об этом.
Я бы также сказал, что ваш дизайн хорош, поскольку вы тесно связали протокол и классы, соответствующие этому протоколу. Если вам действительно нужно поведение, которое вы описали, то одним из решений было бы отказаться от расширений протокола и реализовать
foo
метод внутри каждого класса:
protocol RockInterface {
func foo()
}
class Rock: RockInterface {
init() {
foo()
}
func foo() {
print("You Rock")
}
}
class Metal: Rock {
override func foo() {
print("Metal")
}
}
class Grunge: Rock {
override func foo() {
print("Grunge")
}
}
let rock = Rock() //prints "You Rock"
let metal = Metal() //prints "Metal"
let grunge = Grunge() //prints "Grunge"