在Swift 4中,对原有的Collection
体系作了一些简化。为此,经过这个系列,咱们从新过一遍和Collection
相关的内容。设计
抛开Swift中那些具体的Array
,Set
,Dictionary
不谈,单纯从为了表达一堆数字这个角度来看,其中最基础的动做,就是要能逐个访问到它们。所以,咱们关于集合这个抽象概念自己的话题,不妨就从这个动做开始。code
这里咱们用“一堆数字”这个形式举例便于理解,实际上,做为集合,它表达的是任意一堆对象。视频
为了用最简单的形式描述“逐个访问”这个动做,咱们能够定义一个Protocol
:对象
protocol IteratorProtocol { associatedtype Element mutating func next() -> Element? }
其中,Element
定义了咱们逐个访问到的元素类型,而next
方法则不断给咱们返回下一个元素,全部元素都访问完了,next
返回nil
。另外,为何咱们要用mutating
修饰next
呢?你们先不用在乎这个事情,在后面的内容里,就明白了。接口
有了IteratorProtocol
,怎么用呢?来看个最简单的例子:ci
struct Ones: IteratorProtocol { mutating func next() -> Int? { return 1 } }
这里,One
表示一个包含无穷多个数字1的序列,为了逐个访问到这些数字,咱们只要不断调用next
就行了:文档
var ones = Ones() ones.next() // Optional(1) ones.next() // Optional(1) ones.next() // Optional(1)
虽然例子很简单,但有两点仍是值得说一下:get
Element
的类型,编译器能够从next()
的签名中推导出来;ones
这个序列的内部构成,只要知道调用next
就能够获得下一个元素,或者获得nil
,表示结束就行了;固然,除了这种为了演示而编写的代码以外,咱们也能够定义一些有用的Iterator,例如一个Fibonacci序列:编译器
struct Fibonacci: IteratorProtocol { private var state = (0, 1) mutating func next() -> Int? { let nextNumber = state.0 self.state = (state.1, state.0 + state.1) return nextNumber } }
而用法,和ones
一模一样:
var fibs = Fibonacci() fibs.next() // Optional(0) fibs.next() // Optional(1) fibs.next() // Optional(1) fibs.next() // Optional(2)
看到这,你就明白为何咱们要让next
是一个mutating
方法了。为了遍历序列,咱们几乎老是须要一些用于记录状态的属性,为了让next
能够修改这些属性,必须用mutating
来修饰它。
可是,使用听从IteratorProtocol
的类型来表达序列,有一个让人困惑的地方。当咱们要反复从头遍历一个序列的时候,该怎么办呢?显然,复制一个fibs
并不行,它会从当前遍历的状态继续下去。咱们惟一能作的,就是从新建立一个Fibonacci
对象。
固然,因为Fibonacci
是咱们本身实现的,所以,咱们了解这前先后后的全部细节。可是,当咱们拿着Fibonacci
给别人使用的时候,这种诡异的用法必定不会为你赢得同事的好评。
之因此会有这种问题,是由于咱们借用了遍历的当前状态做为了序列的自己。ones也好,fibs也好,都如此。每一次调用next,咱们用于记录当前遍历状态的值,刚好生成了咱们指望的整个序列。
为了解决这个问题,咱们应该削弱遵循IteratorProtocol
的类型表达的语意,让它在大多时候都只承载遍历的含义,而对于咱们要表达的序列自己,再用一类约束来表达,这就是为何Swift要提供protocol Sequence
的缘由。下一节,咱们就来了解这个protocol
。