为什么indexingIterator.next()使用动态调度? [英] Why is indexingIterator.next() using dynamic dispatch?
问题描述
但是,如果仅使用 range
和 for-in
,则时间分析器将显示协议见证人.
为什么 indexingIterator.next()
使用动态方法,而不在 School
中使用?我以为即使 struct
都符合 protocol
,如果 struct
类型的变量使用 protocol
的方法,则该方法将是静态方法.如果我错了,你能告诉我哪里错了吗?
⬇️学校
代码
struct SchoolIterator:IteratorProtocol {私立var学校列表:学校var idx = 0init(_学校:学校){self.schoolList =学校}更改func next()->细绳?{延迟{idx + = 1}守卫schoolList.count-1> = idx否则{return nil}返回schoolList [idx]}}struct School:序列{fileprivate var list = Array(重复:"school",计数:100000)var count:Int {return list.count}下标(_ idx:Int)->细绳?{守卫idx< = count-1否则{return nil}返回列表[idx]}func makeIterator()->SchoolIterator {返回SchoolIterator(个体)}}var school = School()在学校里上学{打印(学校)}
您的for循环翻译为:
各种学校= School()var iterator = school.makeIterator()而让school = iterator.next(){打印(学校)}
请注意,这里没有什么协议. schools
的类型为 School
, iterator
的类型为 SchoolIterator
,所有 next
确实(例如访问 schoolList.count
或 schoolList
的下标)也处理结构.关键在于,编译器可以准确地找出您的意思,因为它的(编译时)类型是结构.无需查找见证表.
将其与例如
进行比较 func f< S:序列>(_ s:S){对于s {...}/*var迭代器:S.Iterator = s.makeIterator()而让东西= iterator.next(){...}*/}f(学校())f(1 ..< 100)
编译器将如何将调用分派给 iterator.next()
?我特意添加了类型注释,以使发生的事情更清楚-这次,编译器不知道您指的是哪个 next
.是 IndexingIterator.next()
吗?还是 SchoolIterator.next()
?还是 SomeOtherIterator.next()
?请记住,我可以使用任何 Sequence
来调用 f
!这就是为什么它需要在运行时查找 S.Iterator
的实际类型的见证表的原因-无法找出哪个 next
打电话.
至于为什么 for 0中的i..<100
使用动态分派,乍一看,似乎所有结构都如此:
让范围:Range< Int>= 0 ..< 100var iterator:IndexingIterator< Range< Int>>= range.makeIterator()而让我= iterator.next(){...}
但是, iterator.next
实际上会执行 https://medium.com/@venki0119/method-dispatch-in-swift-effects-of-it-on-performance-b5f120e497d3
Why is for-in slower than while in swift debugging mode?
I wrote this.
Thanks for people who answer to me, I could have learned Seqeunce
and IteratorProtocol
.
So I implemented custom type ( School
below code ) which conformed Sequence
.
And I checked Xcode-time profile.
But I can't find anything protocol witness
But If only use range
and for-in
, time profiler show protocol witness.
why is indexingIterator.next()
using dynamic method but not in School
?
I thought that even struct
conformed protocol
, if variable in struct
type use method of protocol
, this method will be static method. If I am wrong, Could you please tell me what is wrong?
⬇️School
code
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)
}
Your for loop translates to:
var schools = School()
var iterator = schools.makeIterator()
while let school = iterator.next() {
print(school)
}
Notice how nothing here is a protocol. schools
is of type School
, iterator
is of type SchoolIterator
, everything that next
does (like accessing schoolList.count
, or the subscript of schoolList
) deals with structs too. The key point is that the compiler can figure out exactly which member you mean, because its (compile-time) type is a struct. There is no need to look up witness tables.
Compare that to, e.g.
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)
How would the compiler dispatch the calls to iterator.next()
? I've deliberately added the type annotation to make it clear what's happening - this time, the compiler doesn't know which next
you mean. Is it IndexingIterator.next()
? Or SchoolIterator.next()
? Or SomeOtherIterator.next()
? Keep in mind that I can call f
with any kind of Sequence
! That's why it needs to look up the witness table of the actual type of S.Iterator
at runtime - it is impossible to figure out which next
to call.
As for why for i in 0..<100
uses dynamic dispatch, well, on first sight, there seems to be all structs:
let range: Range<Int> = 0..<100
var iterator: IndexingIterator<Range<Int>> = range.makeIterator()
while let i = iterator.next() {
...
}
However, iterator.next
actually does something like this:
public mutating func next() -> Elements.Element? { if _position == _elements.endIndex { return nil } let element = _elements[_position] _elements.formIndex(after: &_position) return element }
_elements
is defined like this:
public struct IndexingIterator<Elements: Collection> {
internal let _elements: Elements
_elements
could be any kind of Collection
, so again, we don't know which member _elements[_position]
or _elements.formIndex
refers to at compile time. Is it Array.formIndex
? Or Set.formIndex
? We only know at runtime, when we know what Elements
is.
Recommended reading: https://medium.com/@venki0119/method-dispatch-in-swift-effects-of-it-on-performance-b5f120e497d3
这篇关于为什么indexingIterator.next()使用动态调度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!