SequenceType 與 GeneratorType


Swift 語言中提供了一種 for .. in 語法的形式,用於遍歷集合,比如對於 Array 類型,就可以用 for .. in 來進行遍歷。這個語法在很多其他語言中也有提供,省去了我們定義下標的操作。今天我們要了解的就是關於 for .. in 語法的原理,我們可以讓我們自己的類也支持這個語法。

何為 for .. in

首先,我們先來了解一下 for .. in 的用法,比如這段代碼:

let bookList = ["Swift", "iOS", "Objc"]

for bookName in bookList {

    print(bookName)

}

我們定義了一個數組 bookList, 里面存放了三個字符串。然后我們就可以通過 for ... in 循環進行遍歷。

數組其實就是 Array 類,我們上面的定義如果寫的詳細些,應該是這樣:

let bookList:Array = ["Swift", "iOS", "Objc"]

也就是說,我們傳遞給 for ... in 語法的,其實是一個 Array 類的實例。那么我們再來看看 Array 類的繼承關系:

public struct Array<Element> : CollectionType, MutableCollectionType, _DestructorSafeContainer {
  ...
}

它繼承自一個叫做 CollectionType 的協議,然后我們再來看一下 CollectionType 的定義:

public protocol SequenceType {
  ...
}

經過這么一連串的追溯,其實關鍵就在於這個 SequenceType,一個類如果實現了 SequenceType 協議,那么他就可以使用 for ... in 語法進行遍歷了。包括我們自己的定義的類。

如何實現 SequenceType 協議

那么,既然我們知道了這個特性,我們就可以讓自己定義的類也支持 for .. in 語法。我們先定義一個實體類 Book:

class Book {

    var name:String = ""
    var price:Float = 0.0

    init(name: String, price: Float) {

        self.name = name
        self.price = price

    }

}

Book 類有兩個屬性,一個是書名,一個是價格,然后還有一個構造方法。

接下來,我們再定義一個類 BookList,它實現了 SequenceType 協議,用來表示 Book 實例的列表。不過再實現之前,我們先看一看 SequenceType 協議都需要實現那些接口:

class BookList: SequenceType {

    ...

    typealias Generator = BookListGenerator

    func generate() -> Generator {

        return BookListGenerator(bookList: self.bookList!)

    }

}

SequenceType 協議中定義了一個 typealias Generator 的屬性,這個屬性是一個繼承自 GeneratorType 的類。

SequenceType 還定義了一個 generate 方法,用於返回我們指定的 GeneratorType 類型。

恩。。 怎么又多了個 GeneratorType, 好像有點復雜的樣子。那么咱們繼續看,GeneratorType 是實際生成遍歷信息的接口,我們這里的 BookListGenerator 實現了這個協議,那就來看一下代碼吧:

class BookListGenerator : GeneratorType {

    typealias Element = Book

    var currentIndex:Int = 0
    var bookList:[Book]?

    init(bookList: [Book]) {

        self.bookList = bookList

    }

    func next() -> Element? {

        guard let list = bookList else { return  nil }

        if currentIndex < list.count {

            let element = list[currentIndex]
            currentIndex++
            return element

        }else {

            return nil

        }

    }

}

代碼稍長,請聽我給大家一一分解~

  1. 首先,GeneratorType 定義了一個屬性別名: typealias Element。 我們將 Book 類賦值給它,表示我們這個集合中存儲的數據類型是 Book 類的實例。

  2. 接下來,GeneratorType 還定義了一個 next 方法。用於遍歷這個集合,直到 next 方法返回 nil 的時候,遍歷結束。

func next() -> Element? {

    guard let list = bookList else { return  nil }

    if currentIndex < list.count {

        let element = list[currentIndex]
        currentIndex++
        return element

    }else {

        return nil

    }

}
  1. next 方法中,先用 guard 關鍵字進行了一次判斷,檢查 bookList(也就是實際的數據是否為空),如果為空,就直接返回 nil。 宣告遍歷結束~
  2. 接下來,用了一個叫做 currentIndex 的屬性表示當前所遍歷到得索引,這個屬性的初始值是 0,然后每遍歷一個元素,就加 1,直到它的值超出 list.count 的值,就會返回 nil,宣告遍歷完成~

這樣,我們的 BookListGenerator 就定義完成了(當然,它還聲明了一個構造方法,由於實在簡單,我們就不多說了~)。再次回到繼承自 SequenceType 的 BookList 類中:

class BookList: SequenceType {

    private var bookList:[Book]?

    init() {

        self.bookList = [Book]()

    }

    func addBook(book:Book){

        self.bookList?.append(book)

    }

    typealias Generator = BookListGenerator

    func generate() -> Generator {

        return BookListGenerator(bookList: self.bookList!)

    }

}

這次列出了所有的代碼,還是一一分解~

看了上面關於 BookListGenerator 類的定義,相信就不難理解這里的代碼了:

typealias Generator = BookListGenerator

func generate() -> Generator {

    return BookListGenerator(bookList: self.bookList!)

}

這兩個 SequenceType 接口的方法我們再來觀摩下,typealias 就不用多說了,generate 方法會再遍歷開始的時候調用一次,每次遍歷都會構建一個 Generator 實例,我們這個 BookList 中構建的就是 BookListGenerator,並傳入了 self.bookList(這個是實際的數據列表)以供 BookListGenerator 來進行具體的遍歷操作。

其他方面嘛,BookList 類還定了一個私有屬性,用於實際存放 Book 的列表數據:

private var bookList:[Book]?

還提供了一個構造方法,和一個 addBook 方法,供我們使用,這兩個方法比較簡單,就不多說啦。

使用我們的 SequenceType 類型

好了,我們的 BookList 就這樣完工啦。現在輪到我們檢驗一下了:

let bookList = BookList()

bookList.addBook(Book(name: "Swift", price: 12.5))
bookList.addBook(Book(name: "iOS" , price: 10.5))
bookList.addBook(Book(name: "Objc", price: 20.0))


for book in bookList {

    print("\(book.name) 價格 ¥\(book.price)")

}

大功告成,我們聲明了 BookList 類,然后用 addBook 方法添加幾本書進來。接着我們就可以用 for .. in 來遍歷這個集合啦。

結語

經過這一系列的折騰,我們實現了 SequenceType 和 GeneratorType 類型的定義,並實現 for .. in 的循環遍歷。以及了解了這背后的原理。當然,我在這里也只是給大家介紹了一個點,大家還可以在 swiftdoc.org 查看這幾個協議的詳細文檔,里面介紹的更加全面。

另外,關於 Swift 語言特性知識的內容,還可以看一看這幾篇內容:

最后,感謝大家花了這么長時間把這篇文章看完。希望給大家提供更多有價值的內容,期待大家的寶貴意見。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



猜您在找
 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM