问题描述
Why is for-in slower than while in swift debugging mode?
我写了这个。
感谢回答我的人,我本可以学习 Seqeunce
和 IteratorProtocol
。
所以我实现了符合 School
的自定义类型(Sequence
下面的代码)。
我检查了 Xcode 时间配置文件。
但如果只使用 range
和 for-in
,时间分析器显示协议见证。
为什么 indexingIterator.next()
使用 动态方法 而不是 School
?
我认为即使struct
符合protocol
,如果struct
类型中的变量使用protocol
的方法,该方法将是静态方法。如果我错了,你能告诉我哪里错了吗?
⬇️School
代码
struct SchoolIterator: IteratorProtocol {
private var schoolList: School
var idx = 0
init(_ school: School) {
self.schoolList = school
}
mutating func next() -> String? {
defer { idx += 1 }
guard schoolList.count-1 >= idx
else { return nil }
return schoolList[idx]
}
}
struct School: Sequence {
fileprivate var list = Array(repeating: "school",count: 100000)
var count: Int { return list.count }
subscript(_ idx: Int ) -> String? {
guard idx <= count-1
else { return nil }
return list[idx]
}
func makeIterator() -> SchoolIterator {
return SchoolIterator(self)
}
}
var schools = School()
for school in schools {
print(school)
}
解决方法
您的 for 循环转换为:
var schools = School()
var iterator = schools.makeIterator()
while let school = iterator.next() {
print(school)
}
注意这里没有什么是协议。 schools
属于 School
类型,iterator
属于 SchoolIterator
类型,next
所做的一切(例如访问 schoolList.count
,或 { {1}}) 也处理结构。关键是编译器可以准确地找出您的意思是哪个成员,因为它的(编译时)类型是一个结构体。无需查找见证表。
比较一下,例如
schoolList
编译器如何将调用分派到 func f<S: Sequence>(_ s: S) {
for thing in s {
...
}
/*
var iterator: S.Iterator = s.makeIterator()
while let thing = iterator.next() {
...
}
*/
}
f(School())
f(1..<100)
?我特意添加了类型注释以清楚说明发生了什么 - 这一次,编译器不知道您指的是哪个 iterator.next()
。是next
吗?还是IndexingIterator.next()
?还是SchoolIterator.next()
?请记住,我可以使用任何类型的 SomeOtherIterator.next()
调用 f
!这就是为什么它需要在运行时查找 Sequence
的实际类型的见证表 - 无法确定要调用哪个 S.Iterator
。
至于为什么 next
使用动态分派,嗯,乍一看,似乎都是结构体:
for i in 0..<100
然而,let range: Range<Int> = 0..<100
var iterator: IndexingIterator<Range<Int>> = range.makeIterator()
while let i = iterator.next() {
...
}
实际上做了类似 this 的事情:
public mutating func next() -> Elements.Element? { 如果 _position == _elements.endIndex { 返回 nil } 让元素 = _elements[_position] _elements.formIndex(after: &_position) 返回元素 }
iterator.next
的定义如下:
_elements
public struct IndexingIterator<Elements: Collection> {
internal let _elements: Elements
可以是任何类型的 _elements
,所以同样,我们不知道编译时 Collection
或 _elements[_position]
指的是哪个成员。是_elements.formIndex
吗?还是Array.formIndex
?我们只在运行时知道 Set.formIndex
是什么。
推荐阅读:https://medium.com/@venki0119/method-dispatch-in-swift-effects-of-it-on-performance-b5f120e497d3