Un moyen d'itérer un tuple dans swift?
Je suis curieux de savoir comment faire une boucle for avec un tuple dans swift.
Je sais que pour accéder à chaque membre, vous pouvez utiliser la notation par points en utilisant le numéro d'index
var tupleList = ("A",2.9,3,8,5,6,7,8,9)
for each in tupleList {
println(each)
}
/ / erreur: le Type n'est pas conforme à la séquence de protocole
5 réponses
Oui, vous pouvez!
func iterate<C,R>(t:C, block:(String,Any)->R) {
let mirror = reflect(t)
for i in 0..<mirror.count {
block(mirror[i].0, mirror[i].1.value)
}
}
Et voilà!
let tuple = ((false, true), 42, 42.195, "42.195km")
iterate(tuple) { println("\($0) => \($1)") }
iterate(tuple.0){ println("\($0) => \($1)")}
iterate(tuple.0.0) { println("\($0) => \($1)")} // no-op
Notez que le dernier n'est pas un tuple, donc rien ne se passe (bien qu'il s'agisse d'un tuple 1 ou D'un" Single " auquel le contenu peut être consulté .0
, reflect(it).count
est 0).
, Ce qui est intéressant, c'est que iterate()
peut itérer même d'autres types de collection.
iterate([0,1]) { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }
Et que la collection comprend class
et struct
!
struct Point { var x = 0.0, y = 0.0 }
class Rect { var tl = Point(), br = Point() }
iterate(Point()) { println("\($0) => \($1)") }
iterate(Rect()) { println("\($0) => \($1)") }
Mise en garde: la valeur passée en tant que 2ème argument du bloc est de type Any
. Vous devez le jeter à la valeurs avec le type d'origine.
Swift ne prend actuellement pas en charge l'itération sur les tuples.
Les principales raisons sont:
- Il N'y a aucun moyen à l'exécution de déterminer le nombre d'éléments dans un tuple
- Il N'y a aucun moyen d'accéder à un élément à un index spécifique, sauf pour les accesseurs de compilation comme
tupleList.0
. Vous voudriez vraiment un indicetupleList[0]
mais cela ne nous est pas fourni
Franchement, je ne vois pas pourquoi vous utiliseriez un tuple au lieu d'un tableau si vous voulez itérer sur elle.
Cela n'a pas de sens d'itérer sur un tuple car:
- les Tuples ont toujours une longueur fixe et chaque élément a un type fixe
- Vous pouvez nommer chaque membre tuple avec un nom que vous pouvez utiliser pour y accéder plus tard
Les Tableaux sont bien faits pour itérer sur:
- longueur Arbitraire
- peut stocker plusieurs types en utilisant une superclasse commune ou AnyObject
- peut être déclaré comme un littéral de la même manière que les tuples:
var list = ["A",2.9,3,8,5,6,7,8,9]
@l'excellente solution de dankogai , mise à jour pour Swift 3.0:
func iterate<Tuple>(_ tuple:Tuple, body:(_ label:String?,_ value:Any)->Void) {
for child in Mirror(reflecting: tuple).children {
body(child.label, child.value)
}
}
L'utilisation reste identique aux exemples de @ dankogai (au-delà de Swift 2println()
→print()
Renommer) .
Notez que l'étiquette est maintenant de type String?
quand il était autrefois String
, pour correspondre le changement de type de Swift 1 MirrorType.subscript(…).0
Swift 3 Mirror.Child.label
. Cependant, pour les tuples sans étiquette, l'arg label
revient comme ".0"
, ".1"
, ".2"
, etc.- c'est seulement nil
pour un autre type.
en outre, j'ai pris la liberté de renommer types & args pour mieux correspondre aux normes de nommage solidifiées de Swift 3, et de changer le type de retour de fermeture en Void
.
Sidenote: j'ai remarqué que quelqu'un m'a downvoted ici-Je ne peux pas imaginer pourquoi, autre que l'argument (juste) que la construction de fonctionnalités d'application autour de la réflexion dans Swift pirate le système de type, et est susceptible de conduire à du code merdique tout au long (les tuples de Swift ne devrait pas être considéré comme un type de données abstrait, mais plutôt une petite collection de variables, semblable à des args de méthode). Comme contre-argument, j'ai fini par le porter à Swift 3 dans le projet parce que j'en avais besoin - pour mieux description
s et debugDescription
s. Parce que la sortie de débogage saine vous permettra d'économiser des heures et des heures de frustration. ;- ) De plus, cela pourrait être vraiment utile pour les tests unitaires ... car les tests sont finalement les plus intéressés par "est-ce que le résultat de cette opération correspond à ce que nous attendre?"
, Vous pouvez à l'aide de la réflexion Swift 4
Essayez ceci dans un terrain de jeu:
let tuple = (1, 2, "3")
let tupleMirror = Mirror(reflecting: tuple)
let tupleElements = tupleMirror.children.map({ $0.value })
tupleElements
Sortie:
Non, vous ne pouvez pas. la raison en est que les éléments tuple ne sont pas tous requis pour avoir le même type, donc vous ne seriez pas en mesure de savoir quel type each
devrait avoir.