当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Swift LazySequenceProtocol用法及代码示例


协议

LazySequenceProtocol

normally-eager 序列操作延迟执行的序列。

声明

protocol LazySequenceProtocol : Sequence

概述

惰性序列可用于避免不必要的存储分配和计算,因为它们使用底层序列进行存储并按需计算其元素。例如,此代码示例中的 doubled 是一个包含值 246 的序列。


let doubled = [1, 2, 3].lazy.map { $0 * 2 }

每次访问惰性序列doubled 的元素时,闭包都会访问并转换底层数组的元素。

采用闭包参数的序列操作,例如 map(_:)filter(_:) ,通常是即刻的:它们立即使用闭包并返回一个新数组。当您使用lazy 属性时,您授予标准库显式权限以将闭包和序列存储在结果中,并将计算推迟到需要时。

添加新的惰性操作

要添加新的惰性序列操作,请使用返回惰性包装器的方法扩展此协议,该包装器本身符合 LazySequenceProtocol 。例如,一个 Eager scan(_:_:) 方法定义如下:


extension Sequence {
    /// Returns an array containing the results of
    ///
    ///   p.reduce(initial, nextPartialResult)
    ///
    /// for each prefix `p` of `self`, in order from shortest to
    /// longest. For example:
    ///
    ///     (1..<6).scan(0, +) // [0, 1, 3, 6, 10, 15]
    ///
    /// - Complexity: O(n)
    func scan<Result>(
        _ initial: Result,
        _ nextPartialResult: (Result, Element) -> Result
    ) -> [Result] {
        var result = [initial]
        for x in self {
            result.append(nextPartialResult(result.last!, x))
        }
        return result
    }
}

您可以构建一个序列类型,以延迟计算扫描结果中的元素:


struct LazyScanSequence<Base: Sequence, Result>
    : LazySequenceProtocol
{
    let initial: Result
    let base: Base
    let nextPartialResult:
        (Result, Base.Element) -> Result


    struct Iterator: IteratorProtocol {
        var base: Base.Iterator
        var nextElement: Result?
        let nextPartialResult:
            (Result, Base.Element) -> Result
        
        mutating func next() -> Result? {
            return nextElement.map { result in
                nextElement = base.next().map {
                    nextPartialResult(result, $0)
                }
                return result
            }
        }
    }
    
    func makeIterator() -> Iterator {
        return Iterator(
            base: base.makeIterator(),
            nextElement: initial as Result?,
            nextPartialResult: nextPartialResult)
    }
}

最后,你可以给所有惰性序列一个惰性scan(_:_:)方法:


extension LazySequenceProtocol {
    func scan<Result>(
        _ initial: Result,
        _ nextPartialResult: @escaping (Result, Element) -> Result
    ) -> LazyScanSequence<Self, Result> {
        return LazyScanSequence(
            initial: initial, base: self, nextPartialResult: nextPartialResult)
    }
}

使用这种类型和扩展方法,您可以在任何序列上调用.lazy.scan(_:_:) 来创建延迟计算扫描。生成的 LazyScanSequence 本身也是惰性的,因此进一步的序列操作也会延迟计算。

延迟实现操作的显式权限仅适用于静态已知序列符合 LazySequenceProtocol 的上下文。在以下示例中,由于扩展仅适用于 Sequence ,因此 side-effects (例如 result 的累积)永远不会意外删除或延迟:


extension Sequence where Element == Int {
    func sum() -> Int {
        var result = 0
        _ = self.map { result += $0 }
        return result
    }
}

但是,实际上不要为此使用map,因为它会创建并丢弃结果数组。相反,使用reduce 进行求和操作,或使用forEachfor - in 循环进行有副作用的操作。

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相关用法


注:本文由纯净天空筛选整理自apple.com大神的英文原创作品 LazySequenceProtocol。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。