2017-07-06 6 views
9

Po projekcie połysku dla Swift4 w Xcode 9Zamknięcie krotka nie obsługuje rozpad w Xcode9 Swift4

otrzymuję następujący błąd, który nie mam pojęcia

Zamknięcie parametru krotka „(klucz: _ wartość: _)”nie obsługuje demontażu struktury

Kod:

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) 
     })) 
    } 
} 

Błąd pojawia się w tym momencie try flatMap({ (key, value)in

+0

'Dictionary.init (elementy):' nie można znaleźć w standardzie SWIFT Library. Sam definiujesz? – OOPer

+0

Tak, aktualizuję odpowiedź –

+0

Mam zaktualizowaną odpowiedź –

Odpowiedz

9

Zacznijmy od definicji flatMap do słownika, który jest następujący:

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

Widać, że zamknięcie transform trwa tylko jeden parametr typu Element gdzie Element to tylko typealias dla krotki:

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

Więc pierwsze i tylko argument zamknięcia powinny być krotką z dwóch elementów (key typu Key i value typu Value).


Teraz, jeśli spojrzeć na kod (który kompiluje w Swift 3), widać, że nie jest to przypadek, i powinno być pytanie dlaczego to nawet pracować w Swift 3.

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

Twój zamknięcie trwa 2 argumenty zamiast jednego (key typu Key i value typu Value). Działa to w Swift 3 dzięki funkcji o nazwie destructuring, w której kompilator automatycznie przekształci krotkę 2 elementów w 2 argumenty.

Ale ta funkcja jest dziwne, rzadko używany i daje nieoczekiwane rezultaty większość czasu, więc została ona usunięta w Swift 4.
Edit: Jak podkreślił OOPer, funkcja ta została tymczasowo usunięta w Swift 4 beta, ale powinien zostać ponownie dodany przed ostateczną wersją.

Zamiast tego należy pisać:

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

i Twojego funkcji flatMap staje:

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

Dziękuję za wyjaśnienia. Jest to trzecia biblioteka, którą próbuję dostosować do swift4. –

3

Jest to efektem ubocznym tej propozycji dla Swift 4:

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

Ale niektóre funkcje zawarte w niniejszym wniosku spowodowało pewne regresji która jest skierowana w tym stanowisku evolution-announce mailing list:

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

Tak, można się spodziewać w przyszłości beta lub wersji GM Xcode9, Twój kod będzie się dobrze kompilował ponownie. Do tego czasu, można użyć tego rodzaju obejścia:

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) 
    })) 
} 

Nawiasem mówiąc, w Swift 4, Dictionary ma kilka nowych inicjatorów, które biorą Sequence z (Key, Value) pary. Na przykład:

init(uniqueKeysWithValues: S)