** 這是我的集合系列文章的第一篇,計劃從淺入深通過一系列文章將swift的集合相關內容徹底整理清楚,包括集合類相關的第三方代碼庫,最后自定義一個集合類型,把所有的內容用代碼貫穿起來。**
Generators, Sequences 和 Collections 是swift標準庫的重要組成部分,也是我們編程過程中最常用到的內容,所以理解它們是如何工作的可以很好的提升我們的基本功。如果你能打開playground運行一下本文的代碼,那么會更好的下面的內容。
Generators
我們可以把Generators看做是生成器,它的作用就是提供下一個元素,如果沒有下一個元素則返回nil,標識生產過程結束。從代碼層面看Generator封裝了迭代器的狀態以及迭代器接口。它通過提供一個叫做next()的方法來返回sequence中的下一個元素。
我們可以通過實現 GeneratorType 協議來獲得一個 Generator,
protocol GeneratorType {
associatedtype Element
mutating func next() -> Element?
}
要實現這個協議我們要做的事情并不多,我們只需要讓next()方法返回下一個元素,并且在沒有元素的時候返回nil就可以了。
import Foundation
func pow2(power: Int) -> Int {
return Int(pow(2.0, Double(power)))
}
struct PowersOfTwoGenerator1 : GeneratorType {
associatedtype Element = Int
var power : Int = 0
mutating func next() -> Element? {
return pow2(power++)
}
}
現在我們已經成功的獲得了一個 Generator,我們可以調用它了。
var n = 10
var g = PowersOfTwoGenerator1()
while n > 0 {
n -= 1
println(g.next()!)
}
我們只需要調用next()方法就可以源源不斷的獲得“下一個元素”了,雖然很簡單,但是有一些遺憾,我們只能通過外部的邏輯才能控制元素的個數(在while循環中控制 n
的個數),現在我們計劃把這個工作交給 Generator 自己。
struct PowersOfTwoGenerator2 : GeneratorType {
associatedtype Element = Int
var power : Int = 0
let endPower : Int
init(end : Int) {
endPower = end
}
mutating func next() -> Element? {
return (power < endPower) ? pow2(power++) : nil
}
}
我們給 Generator 一個構造器,通過構造器來設置一個停止生產元素的條件。
var g2 = PowersOfTwoGenerator2(end:10)
while let x = g2.next() {
println(x)
}
只做了一個小改動,是不是讓調用代碼簡潔了很多?
到這里我們可以看到,一個 Generator 能做的工作并不多,一但返回nil,Generator的工作就結束了。
Sequences
sequence首先是一個values的序列,它可以使用for in循環控制結構進行迭代。另一方面sequence是Generator的工廠類,它知道如何生產一個適合的Generator。
我們可以通過實現SequenceType協議來獲得一個sequence,這部分工作也不復雜。
struct PowersOfTwoSequence2 : SequenceType {
associatedtype Generator = PowersOfTwoGenerator2
let endPower : Int
init(end: Int) {
self.endPower = end
}
func generate() -> Generator {
return Generator(end: self.endPower)
}
}
太棒了,我們現在已經獲得一個sequence了,快用for in遍歷一下試試。
for x in PowersOfTwoSequence2(end:10) {
println(x)
}
雖然 PowersOfTwoSequence2 已經可以工作了,但它的實現有一個遺憾,endPower這個屬性需要分別在 PowersOfTwoSequence2 與 PowersOfTwoGenerator2中初始化兩次,我們不能容忍一個屬性如此的放縱.
struct PowersOfTwoSequence4 : SequenceType {
let endPower : Int
init(end: Int) {
self.endPower = end
}
func generate() -> AnyGenerator<Int> {
var power : Int = 0
let nextClosure : () -> Int? = {
(power < self.endPower) ? pow2(power++) : nil
}
return AnyGenerator<Int>(nextClosure)
}
}
在這段代碼里,我們讓 generate() 返回一個 AnyGenerator ,AnyGenerator實現了 GeneratorType 協議,并且可以通過閉包的方式來創建 next() 方法。我們創建一個閉包 nextClosure 并溝通構造器傳遞個 AnyGenerator ,從而完成了 Generator 的創建。因為閉包幫助我們綁定了 endPower ,所以我們解決了 之前屬性需要被初始化兩次的問題。
我們可以通過尾閉包的方式,進一步精簡代碼。
struct PowersOfTwoSequence5 : SequenceType {
let endPower : Int
init(end: Int) {
self.endPower = end
}
func generate() -> AnyGenerator<Int> {
var power : Int = 0
return AnyGenerator<Int> {
(power < self.endPower) ? pow2(power++) : nil
}
}
}
Collections
一個 collection就是一個實現了 startIndex 和 endIndex 并且可以通過下標(subscript)訪問的sequence。collection比sequence更進一步的做到了,允許單個元素可以重復訪問。
集合協議擴展了SequenceType。
public protocol CollectionType : Indexable, SequenceType {
public var startIndex: Self.Index { get }
public var endIndex: Self.Index { get }
public subscript (position: Self.Index) -> Self._Element { get }
}
實現一個集合協議的工作比實現一個SequenceType的工作稍微多一些。
struct PowersOfTwoCollection : CollectionType {
associatedtype Index = Int
let startIndex : Int
let endIndex : Int
init(start:Int, end: Int) {
self.startIndex = start
self.endIndex = end
}
func generate() -> AnyGenerator<Int> {
var power : Int = 0
return AnyGenerator<Int> {
(power < self.endIndex) ? pow2(power++) : nil
}
}
subscript(i: Index) -> Int { return pow2(i) }
}
我們在 PowersOfTwoSequence5 的基礎很容實現 CollectionType 協議。通過構造函數,為collection初始化 startIndex 與 endIndex。提供subscript來為collection提供下標訪問的能力。現在我們擁有一個集合了。
for x in reverse(PowersOfTwoCollection(start:0,end:10)) {
println(x)
}
關于集合,這里只是剛剛開始,如果大家希望了解更多的集合內容,歡迎大家關注我后面的更新。我正在深入的研究swift語言,并將我的學習內容不斷的總結出來,希望能和大家交流共同進步。