SequenceType 與 GeneratorType


Swift 語言中提供了一種 for .. in 語法的形式疫蔓,用于遍歷集合含懊,比如對于 Array 類型身冬,就可以用 for .. in 來進行遍歷。這個語法在很多其他語言中也有提供岔乔,省去了我們定義下標(biāo)的操作酥筝。今天我們要了解的就是關(guān)于 for .. in 語法的原理,我們可以讓我們自己的類也支持這個語法雏门。

何為 for .. in

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

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

for bookName in bookList {

    print(bookName)

}

我們定義了一個數(shù)組 bookList茁影, 里面存放了三個字符串宙帝。然后我們就可以通過 for ... in 循環(huán)進行遍歷。

數(shù)組其實就是 Array 類募闲,我們上面的定義如果寫的詳細些步脓,應(yīng)該是這樣:

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

也就是說,我們傳遞給 for ... in 語法的浩螺,其實是一個 Array 類的實例靴患。那么我們再來看看 Array 類的繼承關(guān)系:

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

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

public protocol SequenceType {
  ...
}

經(jīng)過這么一連串的追溯要出,其實關(guān)鍵就在于這個 SequenceType鸳君,一個類如果實現(xiàn)了 SequenceType 協(xié)議,那么他就可以使用 for ... in 語法進行遍歷了患蹂。包括我們自己的定義的類或颊。

如何實現(xiàn) SequenceType 協(xié)議

那么,既然我們知道了這個特性传于,我們就可以讓自己定義的類也支持 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 類有兩個屬性,一個是書名格了,一個是價格看铆,然后還有一個構(gòu)造方法。

接下來盛末,我們再定義一個類 BookList弹惦,它實現(xiàn)了 SequenceType 協(xié)議,用來表示 Book 實例的列表悄但。不過再實現(xiàn)之前棠隐,我們先看一看 SequenceType 協(xié)議都需要實現(xiàn)那些接口:

class BookList: SequenceType {

    ...

    typealias Generator = BookListGenerator

    func generate() -> Generator {

        return BookListGenerator(bookList: self.bookList!)

    }

}

SequenceType 協(xié)議中定義了一個 typealias Generator 的屬性,這個屬性是一個繼承自 GeneratorType 的類檐嚣。

SequenceType 還定義了一個 generate 方法助泽,用于返回我們指定的 GeneratorType 類型啰扛。

恩。嗡贺。 怎么又多了個 GeneratorType隐解, 好像有點復(fù)雜的樣子。那么咱們繼續(xù)看诫睬,GeneratorType 是實際生成遍歷信息的接口煞茫,我們這里的 BookListGenerator 實現(xiàn)了這個協(xié)議,那就來看一下代碼吧:

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 類賦值給它亲澡,表示我們這個集合中存儲的數(shù)據(jù)類型是 Book 類的實例钦扭。

  2. 接下來,GeneratorType 還定義了一個 next 方法床绪。用于遍歷這個集合客情,直到 next 方法返回 nil 的時候,遍歷結(jié)束会涎。

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 關(guān)鍵字進行了一次判斷,檢查 bookList(也就是實際的數(shù)據(jù)是否為空)末秃,如果為空概页,就直接返回 nil。 宣告遍歷結(jié)束~
  2. 接下來练慕,用了一個叫做 currentIndex 的屬性表示當(dāng)前所遍歷到得索引惰匙,這個屬性的初始值是 0,然后每遍歷一個元素铃将,就加 1项鬼,直到它的值超出 list.count 的值,就會返回 nil劲阎,宣告遍歷完成~

這樣绘盟,我們的 BookListGenerator 就定義完成了(當(dāng)然,它還聲明了一個構(gòu)造方法悯仙,由于實在簡單龄毡,我們就不多說了~)。再次回到繼承自 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!)

    }

}

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

看了上面關(guān)于 BookListGenerator 類的定義沦零,相信就不難理解這里的代碼了:

typealias Generator = BookListGenerator

func generate() -> Generator {

    return BookListGenerator(bookList: self.bookList!)

}

這兩個 SequenceType 接口的方法我們再來觀摩下,typealias 就不用多說了货岭,generate 方法會再遍歷開始的時候調(diào)用一次路操,每次遍歷都會構(gòu)建一個 Generator 實例疾渴,我們這個 BookList 中構(gòu)建的就是 BookListGenerator,并傳入了 self.bookList(這個是實際的數(shù)據(jù)列表)以供 BookListGenerator 來進行具體的遍歷操作屯仗。

其他方面嘛搞坝,BookList 類還定了一個私有屬性,用于實際存放 Book 的列表數(shù)據(jù):

private var bookList:[Book]?

還提供了一個構(gòu)造方法祭钉,和一個 addBook 方法瞄沙,供我們使用,這兩個方法比較簡單慌核,就不多說啦。

使用我們的 SequenceType 類型

好了申尼,我們的 BookList 就這樣完工啦】遄浚現(xiàn)在輪到我們檢驗一下了:

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 來遍歷這個集合啦。

結(jié)語

經(jīng)過這一系列的折騰霹粥,我們實現(xiàn)了 SequenceType 和 GeneratorType 類型的定義灭将,并實現(xiàn) for .. in 的循環(huán)遍歷。以及了解了這背后的原理后控。當(dāng)然庙曙,我在這里也只是給大家介紹了一個點,大家還可以在 swiftdoc.org 查看這幾個協(xié)議的詳細文檔浩淘,里面介紹的更加全面捌朴。

另外,關(guān)于 Swift 語言特性知識的內(nèi)容张抄,還可以看一看這幾篇內(nèi)容:

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

更多精彩內(nèi)容可關(guān)注微信公眾號:
swift-cafe

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末极谊,一起剝皮案震驚了整個濱河市诡右,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怀酷,老刑警劉巖稻爬,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜕依,居然都是意外死亡桅锄,警方通過查閱死者的電腦和手機琉雳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來友瘤,“玉大人翠肘,你說我怎么就攤上這事”柩恚” “怎么了束倍?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盟戏。 經(jīng)常有香客問我绪妹,道長,這世上最難降的妖魔是什么柿究? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任邮旷,我火速辦了婚禮,結(jié)果婚禮上蝇摸,老公的妹妹穿的比我還像新娘婶肩。我一直安慰自己,他們只是感情好貌夕,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布律歼。 她就那樣靜靜地躺著,像睡著了一般啡专。 火紅的嫁衣襯著肌膚如雪险毁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天植旧,我揣著相機與錄音辱揭,去河邊找鬼。 笑死病附,一個胖子當(dāng)著我的面吹牛问窃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播完沪,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼域庇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了覆积?” 一聲冷哼從身側(cè)響起听皿,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宽档,沒想到半個月后尉姨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡吗冤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年又厉,在試婚紗的時候發(fā)現(xiàn)自己被綠了九府。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡覆致,死狀恐怖侄旬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情煌妈,我是刑警寧澤儡羔,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站璧诵,受9級特大地震影響汰蜘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腮猖,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一鉴扫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧澈缺,春花似錦、人聲如沸炕婶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柠掂。三九已至项滑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涯贞,已是汗流浹背枪狂。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宋渔,地道東北人州疾。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像皇拣,于是被迫代替她去往敵國和親严蓖。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容