我很好奇如何在swift中使用元组进行for循环。
我知道要访问每个成员,您可以使用索引号
使用点表示法var tupleList = ("A",2.9,3,8,5,6,7,8,9)
for each in tupleList {
println(each)
}
//错误:类型不符合协议序列
答案 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元组或“单元”,可以访问内容.0
,reflect(it).count
为0)。
有趣的是iterate()
甚至可以迭代其他类型的集合。
iterate([0,1]) { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }
该集合包括class
和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)") }
警告:作为块的第二个参数传递的值是类型Any
。您必须将其强制转换为原始类型的值。
答案 1 :(得分:11)
Swift目前不支持迭代元组。
最大的原因是:
tupleList.0
之类的编译时访问器外,无法访问特定索引处的元素。你真的想要一个下标tupleList[0]
但是没有提供给我们坦率地说,如果你想迭代它,我就无法看到你使用元组而不是数组的原因。
迭代一个元组是没有意义的,因为:
阵列很好地迭代:
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,因为我需要它 - 以获得更好的description
和debugDescription
s 。因为理智的调试输出将为您节省数小时的挫折感。 ;-)另外,这对单元测试非常有用...因为测试最终最感兴趣的是“这个操作的结果是否符合我们的期望?”
答案 3 :(得分:3)
答案 4 :(得分:0)
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
应具有的类型。