在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
。