Protocol

LazySequenceProtocol

A sequence on which normally-eager sequence operations are implemented lazily. あるシーケンス、それにおいては通常は先行な演算は、遅延に実装されます。

Declaration 宣言

protocol LazySequenceProtocol

Overview 概要

Lazy sequences can be used to avoid needless storage allocation and computation, because they use an underlying sequence for storage and compute their elements on demand. For example, doubled in this code sample is a sequence containing the values 2, 4, and 6. 遅延シーケンスは、不必要なストレージの割り当てと計算を防止するために使われることができます。例えば、このコード見本の中のdoubledは、値24、そして6を含んでいるあるシーケンスです。


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

Each time an element of the lazy sequence doubled is accessed, the closure accesses and transforms an element of the underlying array. この遅延シーケンスdoubledの要素がアクセスされるたびごとに、クロージャはその基礎をなす配列の要素にアクセスおよび変換します。

Sequence operations that take closure arguments, such as map(_:) and filter(_:), are normally eager: They use the closure immediately and return a new array. When you use the lazy property, you give the standard library explicit permission to store the closure and the sequence in the result, and defer computation until it is needed. クロージャ引数をとるシーケンス演算、たとえばmap(_:)およびfilter(_:)は、通常は先行です;それらはクロージャを直ちに使います、そして新しい配列を返します。あなたがlazyプロパティを使う場合、あなたは標準ライブラリに明示的な権限を与えて、クロージャとシーケンスを結果に格納します、そして計算をそれが必要とされるまで延期します。

Adding New Lazy Operations 新しい遅延演算を加える

To add a new lazy sequence operation, extend this protocol with a method that returns a lazy wrapper that itself conforms to LazySequenceProtocol. For example, an eager scan(_:_:) method is defined as follows: 新しい遅延シーケンス演算を加えるには、このプロトコルをあるメソッドで拡張してください、それはそれ自身LazySequenceProtocolに準拠するある遅延ラッパーを返すものです。例えば、ある即時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
    }
}

You can build a sequence type that lazily computes the elements in the result of a scan: あなたは、ある走査の結果の中の要素それらを遅延に計算するシーケンス型を構築できます:


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)
    }
}

Finally, you can give all lazy sequences a lazy scan(_:_:) method: 最終的に、あなたは全ての遅延シーケンスをある遅延scan(_:_:)メソッドに与えることができます:


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

With this type and extension method, you can call .lazy.scan(_:_:) on any sequence to create a lazily computed scan. The resulting LazyScanSequence is itself lazy, too, so further sequence operations also defer computation. この型と拡張メソッドで、あなたは.lazy.scan(_:_:)をあらゆるシーケンス上で呼び出して、遅延に計算される走査を作成できます。結果のLazyScanSequenceはそれ自体また遅延です、なのでその先のシーケンス演算もまた計算を延期します。

The explicit permission to implement operations lazily applies only in contexts where the sequence is statically known to conform to LazySequenceProtocol. In the following example, because the extension applies only to Sequence, side-effects such as the accumulation of result are never unexpectedly dropped or deferred: 遅延に演算を実施するための明示的な許可は、そこにおいてシーケンスがLazySequenceProtocolに準拠することを静的に見分けられる文脈においてのみ適用されます。以下の例において、拡張はSequenceに対してのみ適用されることから、副作用それら、たとえばresultの蓄積などは、決して不意に投下されたり延期されたりしません。


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

Don’t actually use map for this purpose, however, because it creates and discards the resulting array. Instead, use reduce for summing operations, or forEach or a for-in loop for operations with side effects. しかしながら、実際にmapをこの目的のために使わないでください、なぜならそれは結果の配列を作成してそして放棄するからです。代わりに、reduceを合計演算のために、またforEachfor-inループを副作用付き演算のために、使ってください。

Topics 話題

Associated Types さまざまな関連型

Instance Properties 様々なインスタンスプロパティ

Instance Methods インスタンスメソッド

Relationships 関係

Inherits From 継承元

Inherited By 継承される先

Conforming Types これらの型が準拠

See Also 参照

Lazy Collections 遅延コレクション