Malheureusement, Swift ne prend pas en charge parameterised extensions (la possibilité d'introduire des variables de type dans les déclarations d'extension), de sorte que vous ne pouvez pas actuellement exprimer directement la notion de "une extension avec une contrainte à certains Set<T>
". Cependant, c'est une partie du manifeste des génériques, donc j'espère que c'est quelque chose qui fait son chemin dans une future version de la langue.
Même si votre extension avec Value
contraint à Set<AnyHashable>
compilé, ce ne serait pas terriblement utile. Vous devez d'abord convertir le dictionnaire souhaité en un [Key: Set<AnyHashable>]
temporaire, puis appeler la méthode de mutation, puis le reconvertir en son type d'origine (en utilisant as!
). Ceci est dû au fait que l'extension est sur un Dictionary
avec des valeurs Set
hétérogènes. Il aurait été parfaitement légal que la méthode d'extension insère éléments arbitrairesHashable
dans l'une des valeurs du dictionnaire. Mais ce n'est pas ce que vous vouliez exprimer.
Dans les cas simples, je dirais qu'il n'y a pas besoin d'une extension en premier lieu. Vous pouvez simplement dire:
var dict = [String: Set<String>]()
dict["key", default: []].insert("someValue")
en utilisant la surcharge de descripteur s » Dictionary
qui prend une valeur par défaut, tel que présenté dans SE-0165.
Si vous voulez toujours une extension, je vous conseille simplement de la rendre plus générique. Par exemple, au lieu de limiter Value
à Set
; le contraindre au protocole SetAlgebra
(auquel Set
est conforme).
Il représente les types qui peuvent effectuer des opérations set-comme et découle également de ExpressibleByArrayLiteral
ce qui signifie que vous pouvez mettre en œuvre votre méthode en utilisant la syntaxe exacte comme ci-dessus:
extension Dictionary where Value : SetAlgebra {
mutating func insert(_ value: Value.Element, at key: Key) {
self[key, default: []].insert(value)
}
}
Bien une chose supplémentaire à considérer ici est la Comportement de copie en écriture des types de collection de Swift tels que Set
. Dans la méthode ci-dessus, le dictionnaire sera interrogé pour une clé donnée, donnant soit un ensemble existant pour cette clé, soit un nouveau vide. Votre value
sera ensuite inséré dans cet ensemble temporaire, et il sera réinséré dans le dictionnaire.L'utilisation d'un temporaire signifie que si l'ensemble est déjà dans le dictionnaire, le value
ne sera pas inséré dans le dictionnaire, le tampon de l'ensemble sera copié en premier afin de préserver la sémantique des valeurs; ce qui pourrait être un problème de performance (ceci est exploré plus en détail dans this Q&A et this Q&A).
Cependant, cela étant dit, je cherche actuellement à résoudre ce problème pour Dictionary
subscript(_:default:)
in this pull request, de sorte que l'ensemble peut être muté en place.
Jusqu'à ce que fixe, la solution est d'abord supprimer l'ensemble du dictionnaire avant de muter:
extension Dictionary where Value : SetAlgebra {
mutating func insert(_ value: Value.Element, at key: Key) {
var set = removeValue(forKey: key) ?? []
set.insert(value)
self[key] = set
}
}
Dans ce cas, l'utilisation d'une extension est pleinement justifiée.
Il est à noter que l'utilisation d'une contrainte de protocole ici est la solution générale (ou solution de contournement dans certains cas) au problème de ne pas avoir d'extensions paramétrées. Il vous permet de réaliser les espaces réservés dont vous avez besoin en tant que types associés de ce protocole. Voir this Q&A pour un exemple de la façon dont vous pouvez créer votre propre protocole à cette fin.