2017-07-06 3 views
9

Nach dem Glanzprojekt für Swift4 in Xcode 9Closure Tupel nicht unterstützt Destrukturierung in Xcode9 Swift4

erhalte ich folgende Fehlermeldung, die ich habe keine Ahnung,

Closure Tupel Parameter ‚(Schlüssel: _, Wert: _)‘nicht unterstützt Destrukturierung

Code:

extension Dictionary 
{ 
    init(elements: [Element]) { 
     self.init() 
     for (key, value) in elements { 
      self[key] = value 
     } 
    } 

    func flatMap<KeyPrime, ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime:ValuePrime] { 
     return Dictionary<KeyPrime, ValuePrime>(elements: try flatMap({ (key, value) in 
      return try transform(key, value) 
     })) 
    } 
} 

Fehler kommt an dieser Stelle try flatMap({ (key, value)in

+0

'Dictionary.init (Elemente:)' nicht in dem Swift Standard Library gefunden werden. Sie definieren es selbst? – OOPer

+0

Ja, ich aktualisiere die Antwort –

+0

Ich habe die Antwort aktualisiert –

Antwort

9

Beginnen wir mit der Definition von flatMap für ein Wörterbuch starten, das ist die folgende:

func flatMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] 

Sie sehen, dass die transform Schließung nur einen Parameter vom Typ nimmt Element wo Element ist nur ein typealias für ein Tupel:

public typealias Element = (key: Key, value: Value) 

So ist die erste und einzige Argument des Verschlusses sollen ein Tupel von zwei Elementen sein (key vom Typ Key und value vom Typ Value).


Nun, wenn Sie in Ihrem Code aussehen (die 3 in Swift kompiliert), werden Sie sehen, dass dies nicht der Fall ist, und Sie sollten fragen, warum dies auch in Swift arbeiten 3.

try flatMap({ (key, value) in 
    return try transform(key, value) 
}) 

Ihre Schließung dauert 2 Argumente statt einer (key vom Typ Key und value vom Typ Value). Dies funktioniert in Swift 3 dank einer Funktion namens Destrukturierung wo der Compiler automatisch ein Tupel von 2 Elementen in 2 Argumente transformiert.

Aber diese Funktion ist seltsam, selten verwendet und gibt unerwartete Ergebnisse die meiste Zeit so hat es in Swift 4.
bearbeiten entfernt: Wie OOPer wies darauf hin, diese Funktion vorübergehend entfernt wurde Swift 4 Beta sollte aber wieder hinzugefügt werden, bevor die finale Version fertig ist.

Stattdessen sollten Sie schreiben werden:

try flatMap({ tupleArgument in 
    return try transform(tupleArgument.key, tupleArgument.value) 
}) 

Und Ihre flatMap Funktion wird:

func flatMap<KeyPrime, ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime:ValuePrime] { 
    return Dictionary<KeyPrime, ValuePrime>(elements: try flatMap({ element in 
     return try transform(element.key, element.value) 
    })) 
} 
+0

Danke für die Erklärung. Es ist eine Third Party Library, die ich mit swift4 kompatibel machen möchte. –

3

Es ist ein Nebeneffekt dieses Vorschlags für Swift 4:

SE-0110 Distinguish between single-tuple and multiple-argument function types.

Aber einige Merkmale in diesem Vorschlag enthalten verursacht einige Regressions, die in diesem Beitrag des evolution-announce mailing list gerichtet:

[swift-evolution-announce] [Core team] Addressing the SE-0110 usability regression in Swift 4

So können Sie in Zukunft Beta oder GM-Version von Xcode9 erwarten, Ihr Code würde wieder gut kompilieren. Bis dahin können Sie diese Art von Abhilfe verwenden:

internal func flatMap<KeyPrime , ValuePrime>(_ transform: (Key, Value) throws -> (KeyPrime, ValuePrime)?) rethrows -> [KeyPrime : ValuePrime] { 
    return Dictionary<KeyPrime,ValuePrime>(elements: try flatMap({ pair in 
     let (key, value) = pair 
     return try transform(key, value) 
    })) 
} 

By the way, in Swift 4, Dictionary hat einige neue initializers die Sequence von (Key, Value) Paar nehmen. Zum Beispiel:

init(uniqueKeysWithValues: S)