我正在测试 CompactMap 的惰性数组,以查找第一个元素并将其映射到几行代码中。
"abc5def".lazy
.compactMap {
print($0)
return Int(String($0))
}.first as Int?
Run Code Online (Sandbox Code Playgroud)
印刷
a
b
c
5
5
Run Code Online (Sandbox Code Playgroud)
为什么最后一个元素被映射两次。如何避免这种行为?
TL;DR该compactMap调用返回一个惰性序列链LazyMapSequence<LazyFilterSequence<LazyMapSequence<...,再加上first需要计算起始索引以及该起始索引处的元素的事实,导致转换闭包被调用两次:
startIndex计算这compactMap是over 的当前实现LazySequenceProtocol(所有惰性序列都遵循的协议):
public func compactMap<ElementOfResult>(
_ transform: @escaping (Elements.Element) -> ElementOfResult?
) -> LazyMapSequence<
LazyFilterSequence<
LazyMapSequence<Elements, ElementOfResult?>>,
ElementOfResult
> {
return self.map(transform).filter { $0 != nil }.map { $0! }
}
Run Code Online (Sandbox Code Playgroud)
这会让你"abc5def".lazy.compactMap { ... }成为一个有型的人LazyMapSequence<LazyFilterSequence<LazyMapSequence<String, Optional<Int>>>, Int>。
其次,您询问的是first惰性序列中的元素。这解决了协议的默认实现(如果它们的基本序列也是一个集合,则所有惰性序列都会自动符合):firstCollectionCollection
public var first: Element? {
let start = startIndex
if start != endIndex { return self[start] }
else { return nil }
}
Run Code Online (Sandbox Code Playgroud)
这意味着first必须检索两条信息:
现在,由于这种实现startIndex,导致重复计算的是计算:LazyFilterSequence
public var startIndex: Index {
var index = _base.startIndex
while index != _base.endIndex && !_predicate(_base[index]) {
_base.formIndex(after: &index)
}
return index
}
Run Code Online (Sandbox Code Playgroud)
subscript上面的实现是LazyMapSequence一个标准的实现:
public subscript(position: Base.Index) -> Element {
return _transform(_base[position])
}
Run Code Online (Sandbox Code Playgroud)
但是,正如您所看到的,转换被再次调用,导致您看到第二个打印结果。
| 归档时间: |
|
| 查看次数: |
1185 次 |
| 最近记录: |