2014-12-05 6 views
5

Wenn eine generische Swift-Typ-Einschränkung ein Protokollname ist, kann ich verlangen, dass zwei Typen, die auf dieses Protokoll beschränkt sind, vom selben Typ sind. Zum Beispiel:Wie sagt man "selbe Klasse" in einem Swift generic

protocol Flier {} 
struct Bird : Flier {} 
struct Insect: Flier {} 
func flockTwoTogether<T:Flier>(f1:T, f2:T) {} 

Die Funktion flockTwoTogether kann mit einem Vogel und einem Vogel oder ein Insekt und ein Insekt, aber nicht mit einem Vogel und ein Insekt genannt werden. Das ist die Einschränkung, die ich möchte. So weit, ist es gut.

Allerdings, wenn ich die gleiche Sache mit einem Klassennamen versuchen, funktioniert es nicht:

class Dog {} 
class NoisyDog : Dog {} 
class WellBehavedDog: Dog {} 
func walkTwoTogether<T:Dog>(d1:T, d2:T) {} 

Das Problem ist, dass ich walkTwoTogether mit einem WellBehavedDog und einem NoisyDog aufrufen können. Das möchte ich verhindern.

Es gibt wirklich zwei Fragen hier:

  • Gibt es eine Möglichkeit zu sagen, dass walkTwoTogether kann nicht mit einem WellBehavedDog und einem NoisyDog genannt werden?

  • Ist das ein Fehler? Ich frage, denn wenn ich kein generisches verwenden kann, um das zu sagen, ist es schwer zu verstehen, warum es für eine generische Constraint überhaupt nützlich ist, ein Klassenname zu sein, da wir das gleiche Ergebnis nur mit einer normalen Funktion erhalten könnten.

+0

Das scheint wie erwartet Verhalten für mich? Sie haben das optionale Element vom Typ Hund eingeschränkt. Beide Unterklassen entsprechen diesem Typ, und nichts in der Deklaration beschränkt sie. Wenn es eine Möglichkeit gäbe, das zu tun, was Sie wollen, würde ich erwarten, dass es eine 'where'-Klausel benötigt, wie in' ', aber das wirft auch ein Error. – cmyr

+0

@cmyr Ja, natürlich habe ich das versucht. Deshalb habe ich gefragt, ob das, was ich tue, nicht ist, wie man es macht, ist es möglich, es zu tun. :) – matt

+0

Alles funktioniert, wenn 'Dog' ein Protokoll ist.Generische Constraints können nicht für Nicht-Protokolltypen erzwungen werden. * (etwas Art Type Erasure) * – mattt

Antwort

3

keine Antwort, per se, aber einige vielleicht mehr Daten ... Das Problem ist, wenn Sie anrufen:

walkTwoTogether(NoisyDog(), WellBehavedDog()) 

Swift kann nur beide Instanzen behandeln, als ob sie Instanzen sind von Dog (aka, upcast) - wir brauchen das, damit wir Methoden für Klasse A mit Unterklassen von A aufrufen können. (Ich weiß, dass Sie das wissen.)

Swift upCast nicht auf Protokolle, so dass der einzige Weg, es zu tun, ist ein Protokoll für die Unterklassen zu spezifizieren, die die Super nicht entsprechen:

protocol Walkable {} 
extension NoisyDog : Walkable {} 
extension WellBehavedDog: Walkable {} 
func walkTwoTogether<T: Dog where T: Walkable>(d1:T, d2:T) { } 

walkTwoTogether(NoisyDog(), WellBehavedDog()) 
// error: type 'Dog' does not conform to protocol 'Walkable' 

die Fehlermeldung zeigt explizit, was los ist - die einzige Möglichkeit, diese Version von walkToTogether ist aufrufen, um die Unterklasse Instanzen Dog, upCast aber Dog entspricht nicht Walkable.

+0

Es ist also ein Glück, dass ich das Problem nicht vorgestellt habe, wie ich es ursprünglich an mich gestellt habe, um Dog von NoisyDog zu unterscheiden! – matt

+0

Keine Unterklassen erlaubt! –

1

Ich würde sagen, dass dies ein Fehler in Betracht gezogen werden sollte, da inout Parameter die Art Anforderungen ändern, wie sie sein sollten:

func walkTwoTogether<T:Dog>(inout d1:T, d2:T) { 

Jetzt hat es das erwartete Verhalten, wo man nur zwei Werte des gleichen Typs passieren kann . (Getestet in Swift 1.2 und Swift 2 Beta 5)

+0

Ja und Nein. Das ist legal: 'var d: Dog = WellBehavedDog(); walkTwoTogether (& d, NoisyDog()) 'Und auf jeden Fall, wenn es einen Bug gibt, denke ich, dass es die Inkonsistenz ist; es ist unklar, _welche _ ist richtig. – matt

+0

@matt Sie haben recht, es könnte beides sein. In Ihrem Fall müssen Sie beide Parameter mit 'inout' markieren. Interessanterweise verhält es sich fast genauso, wenn Sie keine generische Einschränkung verwenden. – Qbyte

+1

Ich bin mehr verwirrt als je zuvor! Aber dein Datum ist interessant, daran besteht kein Zweifel. – matt

Verwandte Themen