2015-11-11 8 views
5

Wenn ich es richtig verstehe, kann Swift den tatsächlichen Typ von Generika auf verschiedene Weise ermitteln, einschließlich der Übereinstimmung nach Rückgabetyp. Der gleiche (oder ein ähnlicher) Mechanismus wird verwendet, um überladene Funktionen zu disambiguieren. So funktioniert das wie erwartet:Swift generische Typauswahl propagiert nicht

func getValue<T>()->T? { 
    return nil 
} 

func getValue()->Int? { 
    return 13 
} 

let b: Int? = getValue() 

Wenn dies ausgeführt wird, b 13 sein wird. Technisch gesehen sind beide Funktionssignaturen passend, aber letzteres ist spezifischer für den angeforderten Rückgabetyp.

Lasst uns eine zweite Funktion und Tunnel den Anruf durch hinzufügen:

func getGetValue<T>()->T? { 
    return getValue() 
} 

let c: Int? = getGetValue() 

Wenn dies ausgeführt wird, c nil sein wird. Tatsächlich wählt der Compiler die generische getValue() - Implementierung aus, die von getGetValue() aufgerufen werden soll, was ich nicht will. IMHO, der angeforderte Rückgabetyp sollte durch das zweite generische propagieren, wenn zwischen den beiden Implementierungen von getValue() gewählt wird, was zu dem gleichen Verhalten wie im ersten Beispiel führt.

Was fehlt mir? (Xcode 7.1)

+0

Excellent find. Meine Vermutung ist, dass der Typ "Ableiten nach Typ" bei einer anderen Abstraktionsebene nicht funktioniert. Innerhalb von "getGetValue" hat der Compiler keine Ahnung, dass der Typ "T" ist, also ist die erste Funktion die einzige, die übereinstimmt. –

+0

@ZoffDino Das wäre meine Vermutung, aber ich verstehe nicht, warum der Compiler die Typen nicht von unten nach oben propagieren kann. Von meinem Standpunkt aus sieht es wie ein Fehler aus - aber ich bin kein Compiler-Typ. Vielleicht gibt es einen absolut gültigen Grund für dieses Verhalten. Ich werde ein Radar einlegen, nur für den Fall. –

+0

Es gibt einen Eintrag im Swift-Blog [Speicher-Sicherheit: Sicherstellen, dass Werte vor der Verwendung definiert sind] (https://developer.apple.com/swift/blog/?id=28), in dem erläutert wird, wie weit der Compiler zum Nachweis der Korrektheit geht des Programms. Ich denke, es ist etwas relevant für Ihre Frage –

Antwort

0

Ich habe versucht, explizit die generische Art zu verbreiten und es immer noch nicht funktioniert (So haben Sie Recht ist dies ein Problem):

func getGetValue<T>()->T? { 
    guard let value: T? = getGetValue() 
    return value 
} 

Hier ist ein etwas anderer Ansatz jedoch, dass könnte das bekommen, was Sie suchen, indem Sie ein Protokoll verwenden (Mithilfe eines Protokolls können wir einige Typinformationen behalten)

Verwandte Themen