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

30
demandé sur Chéyo 2014-06-19 08:56:37

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.

36
répondu dankogai 2014-07-18 18:42:42

Swift ne prend actuellement pas en charge l'itération sur les tuples.

Les principales raisons sont:

  1. Il N'y a aucun moyen à l'exécution de déterminer le nombre d'éléments dans un tuple
  2. 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 indice tupleList[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:

  1. les Tuples ont toujours une longueur fixe et chaque élément a un type fixe
  2. 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:

  1. longueur Arbitraire
  2. peut stocker plusieurs types en utilisant une superclasse commune ou AnyObject
  3. 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]
11
répondu drewag 2014-06-19 05:59:20

@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?"

3
répondu Slipp D. Thompson 2017-09-02 00:35:58

, 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:

entrez la description de l'image ici

2
répondu Menno 2018-05-19 11:22:33

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.

-2
répondu Alex Gaynor 2014-06-19 05:00:35