** 这是我的集合系列文章的第一篇,计划从浅入深通过一系列文章将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语言,并将我的学习内容不断的总结出来,希望能和大家交流共同进步。
网友评论