美文网首页Swift学习
Swift 中的 Sequence(二)

Swift 中的 Sequence(二)

作者: SwiftFun | 来源:发表于2017-06-07 14:36 被阅读46次

    接上篇 Swift 中的 Sequence(一)

    撰写本文时 Swift 版本是 4.0 beta。

    值类型 Iterator 和引用类型 Iterator

    值类型 Iterator

    一般 Iterator 都是值类型的,值类型的 Iterator 的意思是:当把 Iterator 赋值给一个新变量时,是把原 Iterator 的所有状态拷贝了一份赋值给新的 Iterator,原 Iterator 在继续迭代时不会影响新的 Iterator。

    例如用 stride 函数创建一个简单的 Sequence,它从 0 开始,到 9 截止,每次递增 1,即为 [0, 1, 2, ..., 8, 9]。
    然后获取到它的 Iterator,调用 next() 进行迭代。

    let seq = stride(from: 0, to: 10, by: 1)
    var i1 = seq.makeIterator()
    i1.next() // �Optional(0)
    i1.next() // Optional(1)
    

    然后做一个赋值操作,创建一个新的 i2,并把 i1 的值赋给 i2:

    var i2 = i1
    

    再用下面代码做测试

    i1.next() // Optional(2)
    i1.next() // Optional(3)
    i2.next() // Optional(2)
    i2.next() // Optional(3)
    

    从打印的结果会发现:i1 和 i2 是两个独立的 Iterator,他们互不影响,赋值时对 i1 做了一份完整的拷贝。

    所以这里的 Iterator 是一个值类型 Iterator。

    引用类型 Iterator

    可以把任何一个值类型 Iterator 用 AnyIterator 这个包一下就形成了一个引用类型的 Iterator。

    var i3 = AnyIterator(i1)
    var i4 = i3
    

    做以下测试:

    i3.next() // Optional(4)
    i4.next() // Optional(5)
    i3.next() // Optional(6)
    i3.next() // Optional(7)
    

    引用类型的 Iterator,再赋值给一个新的变量后,新的 Iterator 和原 Iterator 在进行迭代时会互相对对方产生影响。

    基于函数的 Sequence、Iterator

    AnyIterator 有一个初始化器,可以传入一个闭包,AnyIterator 会把这个闭包的内容作为调用 next() 时执行的内容。
    这样创建一个 Iterator 时可以不用创建一个新的 class 或 struct。

    例如我们可以这样创建一个斐波那契数列的 Iterator:

    func fibsIterator() -> AnyIterator<Int> {
        var state = (0, 1)
        return AnyIterator {
            let upcomingNumber = state.0
            state = (state.1, state.0 + state.1)
            return upcomingNumber
        }
    }
    

    这样创建出来的 Iterator 是引用类型的。

    然后可以用 AnySequence 来�创建 Sequence,AnySequence 也有一个支持传入闭包的初始化器,于是可以把上面的函数名作为参数传入。

    let fibsSequence = AnySequence(fibsIterator)
    Array(fibsSequence.prefix(10))
    // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
    

    另外,还有一种更简单的方法来创建 Sequence,用 Swift 标准库中的 sequence 函数。

    这个函数有两个变体:
    第一个是 sequence(first:next:)
    第一个参数是 Sequence 中的第一个值,第二个参数传入一个闭包作为 next() 的内容。

    例如创建一个从大到小的随机数 Sequence。

    let randomNumbers = sequence(first: 100) { (previous: UInt32) in
        let newValue = arc4random_uniform(previous)
        guard newValue > 0 else {
            return nil
        }
        return newValue
    }
    
    Array(randomNumbers)
    // [100, 90, 60, 35, 34, 21, 3]
    

    第二个变体是 sequence(state:next:)
    这个要更为强大,它可以在迭代过程中修改状态。

    let fibsSequence2 = sequence(state: (0, 1)) { (state: inout (Int, Int)) -> Int? in
        let upcomingNumber = state.0
        state = (state.1, state.0 + state.1)
        return upcomingNumber
    }
    
    Array(fibsSequence2.prefix(10))
    // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
    

    sequence(frist:next:) 和 sequence(state:next:) 的返回值类型是一个 UnfoldSequence
    在函数式编程中有 foldunfold 的概念。
    fold 是把一系列的值�变为一个值,例如 reduce 就是一个 fold 操作。
    unfold 是 fold 的反�操作,把一个值展开成一系列的值。

    无穷 Sequence 和有穷 Sequence

    上面创建的斐波那契数列 Sequence 是一个无穷 Sequence,意思是如果不设置一个范围,它可以无限的迭代下去。

    因此上面跑测试代码时用了 prefix 方法来取得一个有限的范围。

    有�穷 Sequence 则会在迭代完最后一个值后自动停止迭代。

    SubSequence

    Sequence 的 protocol 定义中有另一个 associatedtype 叫 SubSequence

    protocol Sequence {
        associatedtype Iterator: IteratorProtocol
        
        associatedtype SubSequence
        //...
    }
    

    SubSequence 指定了对原 Sequence 切片后的返回值类型。

    对原 Sequence 进行切片的操作有:

    • prefix and suffix
    • dropFirst and dropLast
    • split

    如果没有指定 SubSequence 的类型,编译器会将其推导为 AnySequence<Iterator.Element> 类型

    Sequence 的稳定性

    由于 Sequence 的协议并没有要求 Sequence 一定是稳定的,所以 Sequence 也可以是不稳定的,也就是说,对 Sequence 进行多次迭代,每次迭代的结果可能会不一样。

    for element in sequence {
        if ... some condition { break }
    }
    
    for element in sequence {
        // No defined behavior
    }
    

    看上面代码,对一个 sequence 进行两次 for-in 循环,如果第一次循环中做了某些破坏稳定性的操作,比如改变了状态,那么进行第二次 for-in 循环的结果是不可预知的。

    如果一个 Sequence 也符合了 Collection 协议,那它一定是稳定的,例如 Array,Collection 协议会确保它是稳定的。

    Swift 标准库中有一些函数创建出来的 Sequence 也能保证是稳定的,比如 stride(from:to:by:)stride(from:through:by:)

    相关文章

      网友评论

        本文标题:Swift 中的 Sequence(二)

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