Протокол и расширение Swift, мне нужно вызвать метод экземпляра, если он присутствует - PullRequest
0 голосов
/ 23 марта 2019

У меня есть протокол Foo и его расширение, например:

protocol Foo {
    func test()    
}

extension Foo {
    func test() {
        print("foo")
    }
}

И у меня также есть классы из протокола:

class Bar: Foo {
    func test() {
        print("bar")
    }
}

И тестер, как показано ниже:

func tester<T: Foo>(_ obj: T) {
   obj.test()
}

let myBar = Bar()
tester(myBar)

На выходе у меня есть:

Foo

Но ожидается - бар

Как я могу вызвать метод экземпляра test() из моего tester

Ответы [ 2 ]

1 голос
/ 23 марта 2019

Все зависит от двух вещей:

  • Это требование протокола или просто добавлено расширением?
  • Приемник печатается как Foo или Bar?

Так, например:

protocol Foo {
    // func test() // note we've commented this out!
}
extension Foo {
    func test() {
        print("foo")
    }
}
class Bar: Foo {
    func test() {
        print("bar")
    }
}
let myBar = Bar()
myBar.test() // bar
let myFoo : Foo = Bar()
myFoo.test() // foo

Но если вы раскомментируете строку, которую я закомментировал, теперь вы всегда получаете "bar" распечатки.

0 голосов
/ 23 марта 2019

Если вы объявите функцию внутри протокола, то она будет динамически отправлена ​​с использованием таблицы-свидетелей, т.е. вы получите переопределенную версию, если вы вызовете ее из производной реализации. Если вы объявляете функцию в расширении (а она не объявлена ​​в протоколе), то функция отправляется статически, и вы получаете версию, основанную на типе, для которого вы ее вызываете (то есть не полиморфизму). Причина этого заключается в том, что компилятор должен знать функцию протокола и объявления переменных во время компиляции, чтобы сгенерировать таблицу-свидетель, и он не может знать обо всех возможных расширениях во время компиляции.

...