在swift中迭代元组有什么方法吗?

rta7y2nd  于 2023-05-16  发布在  Swift
关注(0)|答案(6)|浏览(124)

我很好奇如何在Swift中使用元组进行for循环。
我知道,要访问每个成员,您可以使用点符号使用索引号

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

for each in tupleList {
    println(each)
}

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

2w2cym1i

2w2cym1i1#

你可以的

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元组或“Single”,其中内容可以访问.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。你必须将它转换回原始类型的值。

hkmswyz6

hkmswyz62#

你可以使用反射Swift 5
在Playground试试这个:

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

输出:

vs91vp4v

vs91vp4v3#

Swift目前不支持迭代元组。
最大的原因是:
1.在运行时没有办法确定元组中元素的数量
1.除了像tupleList.0这样的编译时访问器之外,没有办法访问特定索引处的元素。您确实需要一个下标tupleList[0],但我们没有提供
坦率地说,我看不出有什么理由让你使用元组而不是数组来迭代它。
迭代一个元组是没有意义的,因为:
1.元组总是有固定的长度,每个元素都有固定的类型
1.您可以用一个名称来命名每个元组成员,以便以后访问它
数组很适合迭代:
1.任意长度
1.可以使用公共超类或AnyObject存储多个类型
1.可以以类似于元组的方式声明为文字:var list = ["A",2.9,3,8,5,6,7,8,9]

chhqkbe1

chhqkbe14#

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

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

  • 请注意,标签现在的类型是String?,而以前是String,以匹配从Swift 1的MirrorType.subscript(…).0到Swift 3的Mirror.Child.label的类型更改。然而,对于无标签元组,label参数返回为".0"".1"".2"等-对于某些其他类型,它只是nil
  • 此外,我还擅自重命名了types & args,以更好地匹配Swift 3's solidified naming standards,并将闭包返回类型更改为Void
  • 旁注:我注意到有人在这里否决了我--我无法想象为什么,除了(公平的)论点,即在Swift中围绕反射构建应用程序功能是对类型系统的攻击,并且很可能导致整个代码的蹩脚(Swift的元组不应该被视为抽象数据类型,而是一个小的变量集合,类似于方法args)。作为反驳,我最初最终在项目中将其移植到Swift 3,因为我需要它-为了更好的description s和debugDescription s。因为合理的调试输出将为您节省数小时的挫折。;-)此外,这对于单元测试非常有用……因为测试最终最感兴趣的是“这个操作的结果是否与我们期望的相匹配?“*
7bsow1i6

7bsow1i65#

详情

  • 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]
8oomwypt

8oomwypt6#

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

相关问题