Ich denke nicht, dass das gemacht werden kann, aber ich werde trotzdem fragen. Ich habe ein Protokoll:
%Vor%Und eine Klasse:
%Vor%Im Rest meines Codes beziehe ich mich auf alles unter Verwendung des Protokolls X. In diesem Code möchte ich etwas tun können wie:
%Vor% Das Problem ist, dass wenn ich versuche, Equatable
zu implementieren:
Die Idee zu versuchen, die Verwendung von ==
zuzulassen, während die Implementierungen hinter dem Protokoll versteckt werden.
Swift mag das jedoch nicht, weil Equatable
Self
references hat und es mir nicht länger erlaubt, es als Typ zu verwenden. Nur als generisches Argument.
Hat jemand also einen Weg gefunden, einen Operator auf ein Protokoll anzuwenden, ohne dass das Protokoll als Typ unbrauchbar wird?
Der Grund, warum Sie zweimal darüber nachdenken sollten, ein Protokoll konform zu Equatable
zu haben, ist, dass es in vielen Fällen keinen Sinn ergibt. Betrachten Sie dieses Beispiel:
Sie anspielen im Rahmen der Umsetzung von ==
Überprüfung zu geben, aber das Problem ist, dass Sie keine Informationen haben über eine der beiden Arten über sie zu sein Pet
s und Sie wissen nicht, all die Dinge, die ein% sein könnten co_de% (vielleicht fügen Sie später Pet
und Bird
hinzu). Wenn Sie dies wirklich benötigen, können Sie mit einem anderen Ansatz modellieren, wie Sprachen wie C # die Gleichheit implementieren, indem Sie beispielsweise Folgendes tun:
An diesem Punkt, wenn Sie wirklich wollten, könnten Sie Rabbit
implementieren, ohne ==
zu implementieren:
Eine Sache, auf die Sie in diesem Fall achten sollten, ist die Vererbung. Weil Sie einen Erbtyp ablehnen und die Informationen löschen könnten, die Equatable
nicht logisch erscheinen lassen.
Der beste Weg, um zu gehen, ist, nur Gleichheit auf der Klasse / Struktur selbst zu implementieren und einen anderen Mechanismus für Typprüfung zu verwenden.
Wenn Sie Equatable
für ein Protokoll direkt implementieren, ist es nicht länger als Typ verwendbar, was den Zweck der Verwendung eines Protokolls zunichtemacht. Selbst wenn Sie ==
functions nur bei Protokollen ohne Equatable
-Konformität implementieren, können die Ergebnisse fehlerhaft sein. Siehe diesen Beitrag in meinem Blog für eine Demonstration dieser Probleme:
Der Ansatz, den ich am besten finde, ist das Löschen von Typen. Dies ermöglicht ==
Vergleiche für Protokolltypen (in Type-Radiergummis eingeschlossen). Es ist wichtig zu beachten, dass, während wir weiter auf Protokollebene arbeiten, die tatsächlichen ==
Vergleiche an die zugrunde liegenden konkreten Typen delegiert werden, um korrekte Ergebnisse sicherzustellen.
Ich habe einen Typenradierer mit Ihrem kurzen Beispiel erstellt und am Ende etwas Testcode hinzugefügt. Ich habe eine Konstante vom Typ String
zum Protokoll hinzugefügt und zwei konforme Typen erstellt (Strukturen sind am einfachsten zu Demonstrationszwecken), um die verschiedenen Szenarien testen zu können.
Eine ausführliche Erläuterung der verwendeten Löschmethode finden Sie in Teil 2 des obigen Blogposts:
Der folgende Code sollte den Gleichheitsvergleich unterstützen, den Sie implementieren wollten. Sie müssen den Protokolltyp nur in eine Typlöserinstanz umbrechen.
%Vor%Beachten Sie, dass Sie, da der Typradierer dem Protokoll entspricht, Instanzen des Typs radiergummi überall dort verwenden können, wo eine Instanz des Protokolltyps erwartet wird.
Hoffe, das hilft.
Nicht sicher, warum Sie alle Instanzen Ihres Protokolls mit Equatable
übereinstimmen müssen, aber ich bevorzuge es, Klassen ihre Gleichheitsverfahren implementieren zu lassen.
In diesem Fall würde ich das Protokoll einfach lassen:
%Vor% Wenn Sie möchten, dass ein Objekt, das mit MyProtocol
übereinstimmt, auch Equatable
ist, können Sie MyProtocol & Equatable
als Typbeschränkung verwenden:
Auf diese Weise können Sie Ihre Spezifikation klar halten und Unterklassen ihre Gleichheits-Methode nur bei Bedarf implementieren lassen.
Ich rate immer noch davon ab, ==
mit Polymorphismus zu implementieren. Es ist ein bisschen wie ein Code-Geruch. Wenn Sie dem Framework-Benutzer etwas geben wollen, mit dem er die Gleichheit testen kann, dann sollten Sie wirklich eine struct
, nicht eine protocol
verkaufen. Das heißt nicht, dass es nicht die protocol
s sein kann, die die struct
s verkaufen:
Ich denke, dass dies Ihre Absicht effizienter kommuniziert, was im Grunde "Sie haben diese Dinge und Sie wissen nicht, ob sie die gleichen Dinge sind, aber Sie wissen, dass sie die gleichen Eigenschaften haben und Sie können diese testen Eigenschaften sind die gleichen. " Das ist ziemlich ähnlich wie ich das Money
Beispiel implementieren würde.
Sie müssen eine Protokollerweiterung eingeschränkt in Ihren Klassentyp implementieren. Innerhalb dieser Erweiterung sollten Sie den Operator Equatable
implementieren.
Aber ich empfehle Ihnen, die Operator-Implementierung zu Ihrer Klasse hinzuzufügen. Halten Sie es einfach; -)