Реализована ли реализация быстрого расширения по умолчанию при компиляции или во время выполнения?

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

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 ответ

Есть как минимум два фактора, влияющих на поведение, которое вы видите, некоторые из которых находятся под вашим контролем, а некоторые нет.

  1. функции, которые не являются частью требований протокола, отправляются статически. Если вам нужна динамическая отправка, вам нужно добавить метод в объявление протокола:
      protocol RockInterface {
    func foo()
}
  1. однако приведенное выше не решит вашу проблему, поскольку подклассы наследуют таблицу-свидетель протокола родительского класса. Смотрите этот отличный ответ для более подробной информации об этом.

Я бы также сказал, что ваш дизайн хорош, поскольку вы тесно связали протокол и классы, соответствующие этому протоколу. Если вам действительно нужно поведение, которое вы описали, то одним из решений было бы отказаться от расширений протокола и реализовать 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"
Другие вопросы по тегам