Après le projet de gloss pour Swift 4 dans Xcode 9
Je reçois une erreur suivante que je n'ai aucune idée
Le paramètre Tuple de fermeture '(clé: _, valeur: _)' ne prend pas en charge la déstructuration
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)
}))
}
}
Une erreur survient à ce stade try flatMap({ (key, value)in
Commençons par la définition de flatMap
pour un dictionnaire qui est le suivant:
func flatMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
Vous voyez que la fermeture transform
ne prend que n paramètre de type Element
où Element
n'est qu'un typealias
pour un tuple:
public typealias Element = (key: Key, value: Value)
Ainsi, le premier et uniquement argument de la fermeture doit être un Tuple de deux éléments (key
de type Key
et value
de type Value
).
Maintenant, si vous regardez votre code (qui se compile en Swift 3), vous verrez que ce n'est pas le cas, et vous devriez vous demander pourquoi cela fonctionne-t-il même dans Swift 3.
try flatMap({ (key, value) in
return try transform(key, value)
})
Votre fermeture prend 2 arguments au lieu d'un (key
de type Key
et value
de type Value
). Cela fonctionne en Swift 3 grâce à une fonctionnalité appelée destructuring où le compilateur transformera automatiquement un Tuple de 2 éléments en 2 arguments.
Mais cette fonctionnalité est étrange, rarement utilisée et donne la plupart du temps des résultats inattendus, elle a donc été supprimée dans Swift 4.
Edit: Comme indiqué par OOPer, cette fonctionnalité a été temporairement supprimée dans Swift 4 beta mais doit être rajoutée avant que la version finale soit en dehors.
Au lieu de cela, vous devriez écrire:
try flatMap({ tupleArgument in
return try transform(tupleArgument.key, tupleArgument.value)
})
Et votre fonction flatMap
devient:
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)
}))
}
C'est un effet secondaire de cette proposition pour Swift 4:
SE-0110 Distinguer entre les types de fonction à un seul tuple et à plusieurs arguments .
Mais certaines fonctionnalités incluses dans cette proposition ont provoqué une régression qui est abordée dans ce post de la liste de diffusion évolution-annonce :
Donc, vous pouvez vous attendre dans la future version bêta ou GM version de Xcode 9, votre code se compilera bien à nouveau. Jusque-là, vous pouvez utiliser ce type de solution:
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)
}))
}
Par ailleurs, dans Swift 4, Dictionary
a quelques nouveaux initialiseurs qui prennent Sequence
de (Key, Value)
paire. Par exemple:
Je viens de rencontrer cette erreur suite à l'utilisation de enumerated().map()
:
Le paramètre Closure Tuple ne prend pas en charge la déstructuration
J'ai tapé le code:
["foo"].enumerated().map(
Et puis j'ai continué à appuyer Enter jusqu'à ce que Xcode termine automatiquement le passe-partout de fermeture.
La saisie semi-automatique a apparemment un bogue qui provoque l'erreur ci-dessus. La saisie semi-automatique produit une double parenthèse ((offset: Int, element: String))
plutôt que des parenthèses simples (offset: Int, element: String)
.
Je l'ai corrigé manuellement et j'ai pu continuer:
// Xcode autocomplete suggests:
let fail = ["foo"].enumerated().map { ((offset: Int, element: String)) -> String in
return "ERROR: Closure Tuple parameter does not support destructuring"
}
// Works if you manually replace the "(( _ ))" with "( _ )"
let pass = ["foo"].enumerated().map { (offset: Int, element: String) -> String in
return "works"
}
Peut-être le résultat de l'utilisation de Xcode 10.0 beta (10L176w)