美文网首页swift-only 八条精选程序员iOS Developer
彻底搞定集合之:Generators vs Sequences

彻底搞定集合之:Generators vs Sequences

作者: 八条8tiao | 来源:发表于2016-07-23 10:32 被阅读131次

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

    相关文章

      网友评论

        本文标题:彻底搞定集合之:Generators vs Sequences

        本文链接:https://www.haomeiwen.com/subject/kxqwjttx.html