我很好奇如何在Swift中使用元组进行for循环。我知道,要访问每个成员,您可以使用点符号使用索引号
var tupleList = ("A",2.9,3,8,5,6,7,8,9) for each in tupleList { println(each) }
//错误:类型不符合协议顺序
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”,其中内容可以访问.0,reflect(it).count为0)。有趣的是,iterate()甚至可以迭代其他类型的集合。
.0
reflect(it).count
iterate()
iterate([0,1]) { println("\($0) => \($1)") } iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }
这个集合包括class和struct!
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。你必须将它转换回原始类型的值。
Any
hkmswyz62#
你可以使用反射Swift 5在Playground试试这个:
let tuple = (1, 2, "3") let tupleMirror = Mirror(reflecting: tuple) let tupleElements = tupleMirror.children.map({ $0.value }) tupleElements
输出:
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]
tupleList.0
tupleList[0]
var list = ["A",2.9,3,8,5,6,7,8,9]
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()重命名)。
println()
print()
String?
String
MirrorType.subscript(…).0
Mirror.Child.label
label
".0"
".1"
".2"
nil
Void
description
debugDescription
7bsow1i65#
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]
8oomwypt6#
不你不能原因是元组项并不都需要具有相同的类型,因此您无法知道each应该具有什么类型。
each
6条答案
按热度按时间2w2cym1i1#
你可以的
瞧!
注意,最后一个不是元组,所以什么都不会发生(尽管它是一个1元组或“Single”,其中内容可以访问
.0
,reflect(it).count
为0)。有趣的是,
iterate()
甚至可以迭代其他类型的集合。这个集合包括
class
和struct
!警告:作为块的第二个参数传递的值类型为
Any
。你必须将它转换回原始类型的值。hkmswyz62#
你可以使用反射Swift 5
在Playground试试这个:
输出:
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]
chhqkbe14#
@dankogai的优秀解决方案,针对Swift 3.0更新:
用法与@dankogai的示例相同 (除了Swift 2的
println()
→print()
重命名)。String?
,而以前是String
,以匹配从Swift 1的MirrorType.subscript(…).0
到Swift 3的Mirror.Child.label
的类型更改。然而,对于无标签元组,label
参数返回为".0"
,".1"
,".2"
等-对于某些其他类型,它只是nil
。Void
。description
s和debugDescription
s。因为合理的调试输出将为您节省数小时的挫折。;-)此外,这对于单元测试非常有用……因为测试最终最感兴趣的是“这个操作的结果是否与我们期望的相匹配?“*7bsow1i65#
详情
基础解决方案
基础方案使用
加糖
8oomwypt6#
不你不能原因是元组项并不都需要具有相同的类型,因此您无法知道
each
应该具有什么类型。