Betrachte folgenden Spielplatz:
%Vor% Ich verstehe nicht, warum a.f()
und b.f()
return "AAAA"
- sie sollen "CCCC"
zurückgeben, weil func f() -> String
dynamisch gesendet werden sollte (wie im Protokoll deklariert).
Wenn ich class B
so ändere, dass es so aussieht:
dann alle drei Aufrufe an .f()
return "CCCC"
wie erwartet.
Ich glaube, es ist ein Fehler im Swift-Compiler, ich habe Xcode 7.3.1 und 8.0-beta3 eingecheckt, dieses Verhalten ist in beiden reproduzierbar.
Ist das tatsächlich ein erwartetes Verhalten?
Sie sind hier einige Regeln beteiligt.
Manchmal wird die statische Verteilung verwendet (in diesem Fall müssen wir uns den Typ von var / let ansehen, um herauszufinden, welche Implementierung verwendet wird).
Zu anderen Zeiten wird stattdessen dynamischer Versand verwendet (dies bedeutet, dass die Implementierung des Objekts innerhalb der Variablen verwendet wird).
Betrachten wir das allgemeine Beispiel
%Vor%Ich werde die folgenden Definitionen verwenden
classic implementation of f()
, um anzuzeigen, wenn f () außerhalb einer Protokollerweiterung definiert ist (also innerhalb einer Struktur / Klasse).
default implementation of f()
, um anzugeben, obf()
in einer Protokollerweiterung definiert ist.
Wenn SomeType1
ein struct/class
mit seiner eigenen "klassischen" Implementierung von f()
ist, dann wird Polymorphismus angewendet .
Wenn SomeType2
keine klassische Implementierung von f()
hat, wird SomeType1.f()
verwendet. Andernfalls gewinnt SomeType2.f()
.
Wenn SomeType1
keine klassische Implementierung von f()
hat, aber eine Standardimplementierung hat, dann ist Polymorphismus ausgeschaltet .
In diesem Fall wird die Standardimplementierung des Typs let/var
gewonnen.
Schauen wir uns Ihr erstes Beispiel an
%Vor% In diesem A gibt es keine eigene klassische Implementierung (weil es keine Struktur / Klasse ist), sondern eine Standardimplementierung. Daher ist Polymorphismus ausgeschaltet und A.f()
wird verwendet.
Gleiche Regel für Ihr zweites Beispiel
%Vor% B
hat keine klassische Implementierung von f (), hat aber eine Standardimplementierung von f()
. Daher ist Polymorphismus ausgeschaltet und B.f()
(von der Protokollerweiterung) wird verwendet.
Schließlich ist das Objekt vom Typ C
innerhalb einer Konstante vom Typ C
.
Hier hat C
eine klassische Implementierung von f()
. In diesem Fall wird die Protokollimplementierung ignoriert und C.f()
verwendet.
Sehen wir uns ein anderes Beispiel an
%Vor% Wie Sie sehen, gewinnt der Typ der Konstante, die den Wert enthält, wieder. Und wenn Sie das Foo
Objekt in eine Foo
Konstante setzen, erhalten Sie einen Kompilierungsfehler