Collections in Swift 4

在Swift 4中,對原有的Collection體系作了一些簡化。爲此,經過這個系列,咱們從新過一遍和Collection相關的內容。在這個系列裏,咱們拋開Swift中那些具體的Array,Set,Dictionary不談,單純從表達一系列元素這個概念出發,來回顧Swift Collections設計的前先後後,爲何須要Iterator?Index和Iterator的關係和區別是什麼?爲何須要Sequence?Collection和Sequence的差異是什麼?如何爲不一樣的集合類型設計接口?。經過對這些問題的討論,你不只可以通這個系列的內容更好的使用集合類型。還能以一個標準庫庫設計者的視角,來理解一些你可能平時不太會注意到的細節。


從迭代一系列元素開始

泊學4K視頻
泊閱文檔swift

在Swift 4中,對原有的Collection體系作了一些簡化。爲此,經過這個系列,咱們從新過一遍和Collection相關的內容。設計

拋開Swift中那些具體的ArraySetDictionary不談,單純從爲了表達一堆數字這個角度來看,其中最基礎的動做,就是要能逐個訪問到它們。所以,咱們關於集合這個抽象概念自己的話題,不妨就從這個動做開始。code

這裏咱們用「一堆數字」這個形式舉例便於理解,實際上,做爲集合,它表達的是任意一堆對象。視頻

從約束一個最基本的遍歷動做開始

爲了用最簡單的形式描述「逐個訪問」這個動做,咱們能夠定義一個Protocol對象

protocol IteratorProtocol {
        associatedtype Element
        mutating func next() -> Element?
    }

其中,Element定義了咱們逐個訪問到的元素類型,而next方法則不斷給咱們返回下一個元素,全部元素都訪問完了,next返回nil。另外,爲何咱們要用mutating修飾next呢?你們先不用在乎這個事情,在後面的內容裏,就明白了。接口

用IteratorProtocol表示無窮序列

有了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表達序列的侷限性

可是,使用聽從IteratorProtocol的類型來表達序列,有一個讓人困惑的地方。當咱們要反覆從頭遍歷一個序列的時候,該怎麼辦呢?顯然,複製一個fibs並不行,它會從當前遍歷的狀態繼續下去。咱們惟一能作的,就是從新建立一個Fibonacci對象。

固然,因爲Fibonacci是咱們本身實現的,所以,咱們瞭解這前先後後的全部細節。可是,當咱們拿着Fibonacci給別人使用的時候,這種詭異的用法必定不會爲你贏得同事的好評。

之因此會有這種問題,是由於咱們借用了遍歷的當前狀態做爲了序列的自己。ones也好,fibs也好,都如此。每一次調用next,咱們用於記錄當前遍歷狀態的值,剛好生成了咱們指望的整個序列。

What's next?

爲了解決這個問題,咱們應該削弱遵循IteratorProtocol的類型表達的語意,讓它在大多時候都只承載遍歷的含義,而對於咱們要表達的序列自己,再用一類約束來表達,這就是爲何Swift要提供protocol Sequence的緣由。下一節,咱們就來了解這個protocol

相關文章
相關標籤/搜索