Zastanawiam się, czy da się coś takiego osiągnąć.
Mam taki plac zabaw:
protocol Foo {
func testPrint()
}
extension Foo {
func testPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
// Calling self or super go call default implementation
self.testPrint()
print("Call from struct")
}
}
let sth = Bar()
sth.testPrint()
Mogę zapewnić domyślną implementację w, extension
ale co zrobić, jeśli Bar
potrzebuję wszystkiego, co jest w domyślnej implementacji oraz dodatkowych rzeczy?
Jest to trochę podobne do wywoływania super.
metod w class
es w celu spełnienia wymagań implementacji każdej właściwości itp., Ale nie widzę możliwości osiągnięcia tego samego z structs
.
Foo.testPrint(self)()
- problem polega na tym, że nie działa z powodu błędu segmentacji (testowane zarówno na 7.0 GM, jak i 7.1 beta)Odpowiedzi:
Nie wiem, czy nadal szukasz odpowiedzi na to pytanie, ale sposobem na to jest usunięcie funkcji z definicji protokołu, przerzucenie obiektu na obiekt,
Foo
a następnie wywołanie na nim metody:protocol Foo { // func testPrint() <- comment this out or remove it } extension Foo { func testPrint() { print("Protocol extension call") } } struct Bar: Foo { func testPrint() { print("Call from struct") (self as Foo).testPrint() // <- cast to Foo and you'll get the default // function defined in the extension } } Bar().testPrint() // Output: "Call from struct" // "Protocol extension call"
Z jakiegoś powodu działa tylko wtedy, gdy funkcja nie jest zadeklarowana jako część protokołu, ale jest zdefiniowana w rozszerzeniu protokołu. Domyśl. Ale to działa.
źródło
Foo
, gdy protokół nie dziedziczy z żadnego innego protokołu.Cóż, możesz utworzyć zagnieżdżony typ zgodny z protokołem, utworzyć jego instancję i wywołać metodę na tym (nie ma znaczenia, że nie możesz uzyskać dostępu do danych swojego typu, ponieważ implementacja wewnątrz rozszerzenia protokołu i tak nie może się do niego odwoływać). Ale to nie jest rozwiązanie, które nazwałbym eleganckim.
struct Bar: Foo { func testPrint() { // Calling default implementation struct Dummy : Foo {} let dummy = Dummy() dummy.testPrint() print("Call from struct") } }
źródło
Dzięki za post! Jeśli umieścisz definicję funkcji w protokole, to gdy obiekt jest rzutowany jako protokół, widzi on tylko wersję funkcji obiektu, a ponieważ wywołujesz ją w sobie, otrzymasz nowy adres Apple ...
Wypróbowałem wersję taką jak ta:
import UIKit protocol MyProc { } protocol MyFuncProc { func myFunc() } extension MyProc { func myFunc() { print("Extension Version") } } struct MyStruct: MyProc, MyFuncProc { func myFunc() { print("Structure Version") (self as MyProc).myFunc() } } (MyStruct() as MyFuncProc).myFunc()
Daje to wynik:
Structure Version Extension Version
źródło
Jeśli twój protokół ma
associatedType
lubSelf
wymagania, obsada nie będzie działać. Aby obejść ten problem, utwórz domyślną implementację „cienia”, którą może wywoływać zarówno zwykła domyślna implementacja, jak i zgodny typ.protocol Foo { associatedType Bar } extension Foo { func testPrint() { defaultTestPrint() } } fileprivate extension Foo { // keep this as private as possible func defaultTestPrint() { // default implementation } } struct Bar: Foo { func testPrint() { // specialized implementation defaultTestPrint() } }
źródło
defaultXX()
jest dużo bardziej wyrazisty i czytelny niż inne odpowiedzi.co myślisz o takim sposobie naprawienia tego?
protocol Foo { func testPrint() } extension Foo { func testPrint() { defaultTestPrint() } func defaultTestPrint() { print("Protocol extension call") } } struct Bar: Foo { func testPrint() { // Calling self or super go call default implementation defaultTestPrint() print("Call from struct") } } let sth = Bar() sth.testPrint()
źródło
Mam na to rozwiązanie.
Kwestia
Jeśli masz domyślną implementację w rozszerzeniu, podczas implementowania protokołu do innej klasy / struktury, tracisz tę domyślną implementację, jeśli zaimplementujesz metodę. Jest to zgodne z projektem, tak działają protokoły
Rozwiązanie
Przykład
protocol Foo { var defaultImplementation: DefaultImpl? { get } func testPrint() } extension Foo { // Add default implementation var defaultImplementation: DefaultImpl? { get { return nil } } } struct DefaultImpl: Foo { func testPrint() { print("Foo") } } extension Foo { func testPrint() { defaultImplementation?.testPrint() } } struct Bar: Foo { var defaultImplementation: DefaultImpl? { get { return DefaultImpl() } } func testPrint() { if someCondition { defaultImplementation?.testPrint() // Prints "Foo" } } } struct Baz: Foo { func testPrint() { print("Baz") } } let bar = Bar() bar.testPrint() // prints "Foo" let baz = Baz() baz.testPrint() // prints "Baz"
Wady
Tracisz wymagany błąd implementacji w strukturze / klasie, w której implementujesz ten protokół.
źródło