當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。