Iterators
在我们研究Sequence
之前,我们先从我们日常比较常见的一段代码入手:
let numbers = [2,4,6,8]
for num in numbers{
print(num)
}
系统的底层是如何实现for...in
,接下来我们通过SIL
观察一下:
// function_ref Collection<>.makeIterator() 这里创建一个makeIterator
%34 = function_ref @(extension in Swift):Swift.Collection< where A.Iterator == Swift.IndexingIterator<A>>.makeIterator() -> Swift.IndexingIterator<A> : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in τ_0_0) -> @out IndexingIterator<τ_0_0> // user: %35
%35 = apply %34<Array<Int>>(%29, %32) : $@convention(method) <τ_0_0 where τ_0_0 : Collection, τ_0_0.Iterator == IndexingIterator<τ_0_0>> (@in τ_0_0) -> @out IndexingIterator<τ_0_0>
dealloc_stack %32 : $*Array<Int> // id: %36
br bb1 // id: %37
bb1: // Preds: bb3 bb0
%38 = alloc_stack $Optional<Int> // users: %43, %44, %41
%39 = begin_access [modify] [static] %29 : $*IndexingIterator<Array<Int>> // users: %42, %41
// function_ref IndexingIterator.next()
%40 = function_ref @Swift.IndexingIterator.next() -> A.Element? : $@convention(method) <τ_0_0 where τ_0_0 : Collection> (@inout IndexingIterator<τ_0_0>) -> @out Optional<τ_0_0.Element> // user: %41
%41 = apply %40<Array<Int>>(%38, %39) : $@convention(method) <τ_0_0 where τ_0_0 : Collection> (@inout IndexingIterator<τ_0_0>) -> @out Optional<τ_0_0.Element>
end_access %39 : $*IndexingIterator<Array<Int>> // id: %42
%43 = load %38 : $*Optional<Int> // user: %45
dealloc_stack %38 : $*Optional<Int> // id: %44
switch_enum %43 : $Optional<Int>, case #Optional.some!enumelt.1: bb3, case #Optional.none!enumelt: bb2 // id: %45
可以看到,这里调用了Collection
协议中的makeIterator()
方法,创建了一个indexingIterator
,接着调用indexingIterator.next()
方法来不断拿到元素,也就意味着我们平常写的for...in
是不存在的,for...in
是一个语法糖。
我们来找到Sequence.swift
这个文件,IteartorProtocol
是一个一次提供一个序列值的类型,它和Sequence
协议是息息相关的,Sequence
每次通过创建迭代器来访问序列中的元素。
所以我们每次在使用for..in
的时候,其实都是使用这个集合的迭代器来遍历当前集合或者序列当中的元素。
我们来看一下IteratorProtocol
的定义:
public protocol IteratorProtocol {
/// The type of element traversed by the iterator.
//关联类型,实现该协议时,需要执行Element的类型
associatedtype Element
mutating func next() -> Element?
}
当前协议有一个关联类型Element
,其实有一个mutating
的方法next
,next
方法返回一个element
。
接下来就是Sequence
协议的定义
public protocol Sequence {
/// A type representing the sequence's elements.
associatedtype Element
/// A type that provides the sequence's iteration interface and
/// encapsulates its iteration state.
associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
/// A type that represents a subsequence of some of the sequence's elements.
// associatedtype SubSequence: Sequence = AnySequence<Element>
// where Element == SubSequence.Element,
// SubSequence.SubSequence == SubSequence
// typealias SubSequence = AnySequence<Element>
/// Returns an iterator over the elements of this sequence.
__consuming func makeIterator() -> Iterator
......
}
对于Sequence
协议来说,表达的是既可以是一个有限的集合,也可以是一个无限的集合,而它只需要提供集合中的元素,和如何访问这些元素的接口即可。
我们来自定义的试一下:假设我们要用一个结构体来模拟一个集合,对于一个给定的初始值,那么当前集合中包含从 0...count
的整形集合。
struct LGSequence:Sequence {
typealias Element = Int
var arrayCount: Int
func makeIterator() -> LGIterator {
return LGIterator(self)
}
}
struct LGIterator: IteratorProtocol {
typealias Element = Int
let seq: LGSequence
init(_ sequence : LGSequence) {
self.seq = sequence
}
var count = 0
mutating func next() -> Int? {
guard count < self.seq.arrayCount else {
return nil
}
count += 1
return count
}
}
let seq = LGSequence.init(arrayCount: 10)
for element in seq{
print(element)
}
·······························
1
2
3
4
5
6
7
8
9
10
网友评论