2017-02-23 2 views
1

Kann mir jemand erklären, warum der letzte Fall in diesem Beispiel ein Kompilierungsfehler ist?Generische Funktionen und Unterklassen. Kann jemand diesen Kompilierungsfehler erklären?

class A{} 
class B: A{} 

protocol Finder{ 
    func find< T: A>(_ f: (T)->Bool) -> T? 
} 

class FinderImpl : Finder{ 
    func find<T : A>(_ f: (T) -> Bool) -> T? { 
     //In the real code I use T to find the instance. I.e. CoreData 
     return nil 
    } 
} 

let finder = FinderImpl() 

//OK 
let optionalB : B? = finder.find{_ in true} 
let a : A = finder.find{_ in true}! 
let b : B = finder.find{(b: B) in true}! 

//Compile Error 
let b2 : B = finder.find{_ in true}! 

lassen a. Der Compiler verwendet (A) -> Bool. als den Schließungstyp. Dann ist der Rückgabetyp A.

lassen b. Dies wird kompiliert, da der Verschluss explizite Informationen enthält: (B)->Bool

lassen Sie optionalB. Ich frage mich, warum dieser Fall funktioniert, hier hat die Schließung auch keine Informationen. Der Unterschied ist die ! operator

Der Fehler: Im letzten Fall wird der Compiler übergeben, die Art des Verschlusses zu schließen, versagt finden Func. Es schlägt mir vor, as! B zu werfen, weil es denkt, dass der Verschlusstyp (A)->Bool ist. Es wird nicht mit den Referenztyp von b2 B.

Wichtig: ich nicht as! B werfen kann, weil ich die Suchfunktion benötigen tatsächlich den Typ B zu verwenden, wenn ich as! B werfen, wird die Funktion des Typs A verwenden und erhalten die falsche Instanz. Der Code würde kompilieren, aber die Ergebnisse wären falsch.

Wenn ich die T:A Einschränkung entfernen, gibt es keinen Kompilierungsfehler.

Das sieht für mich wie ein Compiler-Fehler aus. Ich denke, der Compiler sollte den Typ von b2 verwenden, um zu wissen, dass der Abschluss (B)->Bool und dann der Ergebnistyp von Find ist. Die T:A Einschränkung und das Fehlen von Typinformationen in der Schließung führt dazu, dass es fehlschlägt.

Fehle ich hier etwas? Irgendwelche Gedanken?

Antwort

0

Da Swift den Rückgabetyp im letzten Beispiel nicht ableiten kann.

In Ihrer generischen Funktion, erklären Sie, dass TA oder eine Unterklasse von A sein muss:

func find<T : A>(_ f: (T) -> Bool) -> T? { 
    return nil 
} 

Swift kann geschlossen werden, was T tatsächlich ist, wenn Sie den Typen in der Schließung angeben. Deshalb ist diese gearbeitet:

finder.find{(b: B) in true}! 
       ^now T == B 

Hier legen Sie keine Art Informationen geliefert hat, so das einzige, was der Compiler stützte sich auf die Deklaration der generische Funktion ist, die sagt T : A:

finder.find{ _ in true}! // this return A 
      ^what type is this? The compiler doesn't have any extra 
       information so it must be A according to the declaration 

Sie können bekommen es Compiler durch eine explizite Umwandlung machen:

let b2 : B = finder.find{ _ in true}! as! B 

Oder bieten die Typinformationen:

let b3 : B = finder.find{ (_: B) in true}! 

(Dies ist nur um zu kompilieren.Der Code wird offensichtlich zur Laufzeit abstürzen, weil Sie einen Nullwert zwangsentpacken)

+0

Hallo, Danke für Ihre Antwort. Ich verstehe Ihre Punkte, ich denke, ich habe das auch in der Frage erwähnt. Was ich als ein Problem sehe, ist, dass ich in b2: B tatsächlich die Typinformation spezifiziere. T = B. Ich sehe nicht, warum es notwendig wäre, (B) -> Bool auch explizit anzugeben. Nimm zum Beispiel das optionale B, dort gebe ich nicht den Schließungstyp an, aber es funktioniert. Deshalb denke ich, dass dies ein Compiler Bug sein könnte. Irgendwelche Gedanken? – Lio

Verwandte Themen