有什么方法可以在swift中迭代一个元组?

Ché*_*éyo 35 swift

我很好奇如何在swift中使用元组进行for循环.

我知道要访问每个成员,您可以使用索引号使用点表示法

var tupleList = ("A",2.9,3,8,5,6,7,8,9)

for each in tupleList {
    println(each)
}
Run Code Online (Sandbox Code Playgroud)

//错误:类型不符合协议序列

dan*_*gai 40

是的你可以!

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

瞧!

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
Run Code Online (Sandbox Code Playgroud)

请注意,最后一个不是元组,因此没有任何反应(尽管它是1元组或"单个",可以访问内容.0,reflect(it).count是0).

有趣的是,iterate()甚至可以迭代其他类型的集合.

iterate([0,1])              { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }
Run Code Online (Sandbox Code Playgroud)

该系列包括classstruct!

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)") }
Run Code Online (Sandbox Code Playgroud)

警告:作为块的第二个参数传递的值是type Any.您必须将其强制转换为原始类型的值.

  • Jafar,我不认为[文件](https://developer.apple.com/library/watchos/documentation/Swift/Reference/Swift_Mirror_Structure/index.html)暗示镜子将被游乐场和调试器_only_.文档中具体说明的是"游乐场和调试器使用镜子". (3认同)

dre*_*wag 10

Swift目前不支持迭代元组.

最大的原因是:

  1. 在运行时无法确定元组中元素的数量
  2. 除了编译时访问器之外,无法访问特定索引处的元素tupleList.0.你真的想要一个下标tupleList[0]但是没有提供给我们

坦率地说,如果你想迭代它,我看不出你会使用元组而不是数组的原因.

迭代元组是没有意义的,因为:

  1. 元组始终具有固定长度,并且每个元素都具有固定类型
  2. 您可以使用可用于稍后访问它的名称为每个元组成员命名

数组很好地迭代:

  1. 任意长度
  2. 可以使用公共超类或AnyObject存储多个类型
  3. 可以与元组类似的方式声明为文字: var list = ["A",2.9,3,8,5,6,7,8,9]

  • 我想迭代一个从函数中出来的元组。 (2认同)

Men*_*nno 8

您可以使用反射Swift 4

在操场上尝试一下:

let tuple = (1, 2, "3")
let tupleMirror = Mirror(reflecting: tuple)
let tupleElements = tupleMirror.children.map({ $0.value })
tupleElements
Run Code Online (Sandbox Code Playgroud)

输出:

在此处输入图片说明


Sli*_*son 5

@dankogai 的优秀解决方案,针对 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法与@dankogai 的示例相同(除了 Swift 2 的println()? print()rename)

请注意,标签现在String?是以前String的类型,以匹配从 Swift 1MirrorType.subscript(…).0到 Swift 3 的类型更改Mirror.Child.label。然而,对于labelless元组labelARG回来为".0"".1"".2"等-这只是nil一些其他类型。

此外,我冒昧地重命名类型和参数以更好地匹配Swift 3 的固化命名标准,并将闭包返回类型更改为Void.

旁注:我注意到有人在这里对我投了反对票——我无法想象为什么,除了(公平的)论点,在 Swift 中围绕反射构建应用程序功能正在侵入类型系统,并且可能会导致整个代码都很糟糕(Swift 的元组应该'不被视为抽象数据类型,而是一小部分变量集合,类似于方法 args)。作为反驳,我最初最终在项目中将其移植到 Swift 3,因为我需要它——为了更好的descriptions 和debugDescriptions。因为健全的调试输出将为您节省数小时的挫折感。;-) 此外,这对于单元测试可能非常有用……因为测试最终最感兴趣的是“此操作的结果是否符合我们的预期?”