LazySequenceProtocol
声明
protocol LazySequenceProtocol : Sequence
概述
惰性序列可用于避免不必要的存储分配和计算,因为它们使用底层序列进行存储并按需计算其元素。例如,此代码示例中的 doubled
是一个包含值 2
、 4
和 6
的序列。
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
进行求和操作,或使用forEach
或for
- in
循环进行有副作用的操作。
可用版本
相关用法
- Swift LazySequence split(maxSplits:omittingEmptySubsequences:whereSeparator:)用法及代码示例
- Swift LazySequence suffix(from:)用法及代码示例
- Swift LazySequence allSatisfy(_:)用法及代码示例
- Swift LazySequence map(_:)用法及代码示例
- Swift LazySequence last用法及代码示例
- Swift LazySequence elementsEqual(_:)用法及代码示例
- Swift LazySequence shuffled()用法及代码示例
- Swift LazySequence enumerated()用法及代码示例
- Swift LazySequence dropLast(_:)用法及代码示例
- Swift LazySequence sorted()用法及代码示例
- Swift LazySequence firstIndex(where:)用法及代码示例
- Swift LazySequence lastIndex(where:)用法及代码示例
- Swift LazySequence last(where:)用法及代码示例
- Swift LazySequence index(_:offsetBy:limitedBy:)用法及代码示例
- Swift LazySequence firstIndex(of:)用法及代码示例
- Swift LazySequence randomElement()用法及代码示例
- Swift LazySequence first(where:)用法及代码示例
- Swift LazySequence contains(where:)用法及代码示例
- Swift LazySequence index(_:offsetBy:)用法及代码示例
- Swift LazySequence randomElement(using:)用法及代码示例
- Swift LazySequence compactMap(_:)用法及代码示例
- Swift LazySequence first用法及代码示例
- Swift LazySequence subscript(_:)用法及代码示例
- Swift LazySequence max()用法及代码示例
- Swift LazySequence suffix(_:)用法及代码示例
注:本文由纯净天空筛选整理自apple.com大神的英文原创作品 LazySequenceProtocol。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。