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

时间:2014-06-19 04:56:38

标签: swift

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

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

使用点表示法
var tupleList = ("A",2.9,3,8,5,6,7,8,9)

for each in tupleList {
    println(each)
}

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

6 个答案:

答案 0 :(得分:37)

是的,你可以!

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)
    }
}

瞧!

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

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

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

iterate([0,1])              { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }

该集合包括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)") }

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

答案 1 :(得分:11)

Swift目前不支持迭代元组。

最大的原因是:

  1. 在运行时无法确定元组中元素的数量
  2. 除了tupleList.0之类的编译时访问器外,无法访问特定索引处的元素。你真的想要一个下标tupleList[0]但是没有提供给我们
  3. 坦率地说,如果你想迭代它,我就无法看到你使用元组而不是数组的原因。

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

    1. 元组始终具有固定长度,并且每个元素都具有固定类型
    2. 您可以使用可用于稍后访问的名称命名每个元组成员
    3. 阵列很好地迭代:

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

答案 2 :(得分:3)

@dankogai's excellent solution,针对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)
    }
}

用法与@ dankogai的示例相同(除了Swift 2的println()print()重命名)

请注意,标签现在属于String?类型(以前为String),以匹配从Swift 1的MirrorType.subscript(…).0到Swift 3的Mirror.Child.label的类型更改1}}。但是,对于无标签元组,label arg会返回".0"".1"".2"等等。对于其他一些类型,它只有nil

此外,我冒昧地重命名类型&amp; args更好地匹配Swift 3's solidified naming standards,并将闭包返回类型更改为Void

旁注:我注意到有人在这里向我倾斜 - 我无法想象为什么,除了(合理的)论证在Swift中围绕反射构建应用程序功能是黑客攻击类型系统,并且很可能导致整个糟糕的代码(Swift的元组不应该被视为抽象数据类型,而是一小部分变量,类似于方法args)。作为一个反驳论点,我最初将其移植到项目中的Swift 3,因为我需要它 - 以获得更好的descriptiondebugDescription s 。因为理智的调试输出将为您节省数小时的挫折感。 ;-)另外,这对单元测试非常有用...因为测试最终最感兴趣的是“这个操作的结果是否符合我们的期望?”

答案 3 :(得分:3)

您可以使用反射 Swift 4

在游乐场试试这个:

u ^ v

输出:

enter image description here

答案 4 :(得分:0)

详细信息

  • Xcode 11.2.1(11B500),Swift 5.1

基本解决方案

struct Tuple<T> {
    let original: T
    private let array: [Mirror.Child]
    init(_ value: T) {
        self.original = value
        array = Array(Mirror(reflecting: original).children)
    }
    func forEach(closure: (Mirror.Child) -> Void) { array.forEach { closure($0) } }
    func getOnlyValues<T: Any>() -> [T] { array.compactMap { $0.value as? T } }
    func getAllValues() -> [Any] { array.compactMap { $0.value } }
}

在基本解决方案上的用法

let num: Int? = 3
let str: String? = nil
let x = (1, "stew", str, 5.4, 2, num)

let tuple = Tuple(x)
tuple.forEach { print("\($0)") }

print("\(tuple.getAllValues())")            // [1, "stew", nil, 5.4, 2, Optional(3)]
print("\(tuple.getOnlyValues() as [Int])")  // [1, 2, 3]

更多的糖

func valuesFrom<V>(tuple: V) -> [Any] { return Tuple(tuple).getAllValues() }
func onlyValuesFrom<T,V>(tuple: V) -> [T] { return Tuple(tuple).getOnlyValues() as [T] }

print(valuesFrom(tuple: x))                 // [1, "stew", nil, 5.4, 2, Optional(3)]
print(onlyValuesFrom(tuple: x) as [Int])    // [1, 2, 3]

答案 5 :(得分:-2)

不,你不能。原因是元组项目并非都需要具有相同的类型,因此您将无法知道each应具有的类型。