为什么 indexingIterator.next() 使用动态调度?

Why is indexingIterator.next() using dynamic dispatch?

我写了这个。 感谢那些回答我的人,我本可以学到 SeqeunceIteratorProtocol.

所以我实现了符合 Sequence 的自定义类型(School 下面的代码)。 我检查了 Xcode 时间配置文件。

但我找不到任何东西协议见证

但是如果只使用 rangefor-in ,时间分析器显示 protocol witness.

为什么 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)
}

注意这里什么都不是协议。 schoolsSchool 类型,iteratorSchoolIterator 类型,next 所做的一切(比如访问 schoolList.count,或 schoolList.count 的下标=20=]) 也处理结构。关键是编译器可以准确地弄清楚你指的是哪个成员,因为它的(编译时)类型是一个结构。无需查找 witness tables.

将其与

进行比较
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()?请记住,我可以用任何类型的 Sequence 调用 f!这就是为什么它需要在运行时 查找 S.Iterator 实际类型的见证 table - 不可能找出 next 到哪个 next打电话。

至于为什么for i in 0..<100使用动态调度,嗯,乍一看,似乎所有的结构:

let range: Range<Int> = 0..<100
var iterator: IndexingIterator<Range<Int>> = range.makeIterator()
while let i = iterator.next() {
    ...
}

然而,iterator.next 实际上做了类似 this 的事情:

public 变异函数 next() -> Elements.Element? { 如果 _position == _elements.endIndex { return 无 } 让元素 = _elements[_position] _elements.formIndex(之后:&_position) return 元素 }

_elements 定义如下:

public struct IndexingIterator<Elements: Collection> {
  
  internal let _elements: Elements

_elements 可以是任何类型的 Collection,所以同样,我们不知道在编译时 _elements[_position]_elements.formIndex 指的是哪个成员。是Array.formIndex吗?还是Set.formIndex?我们只在运行时知道,当我们知道 Elements 是什么时。

推荐阅读:https://medium.com/@venki0119/method-dispatch-in-swift-effects-of-it-on-performance-b5f120e497d3