当延迟映射一个值数组时,我会收到一个预期类型为LazyMapSequence
的实例:
Welcome to Apple Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50).
Type :help for assistance.
1> let numbers = Array(1...5)
numbers: [Int] = 5 values {
[0] = 1
[1] = 2
[2] = 3
[3] = 4
[4] = 5
}
2> let squares = numbers.lazy.map { $0 * $0 }
squares: LazyMapSequence<LazySequence<[Int]>.Elements, Int> = {
_base = 5 values {
[0] = 1
[1] = 2
[2] = 3
[3] = 4
[4] = 5
}
_transform =
}
但是,如果map(_:)
方法接收到抛出闭包,则映射不会延迟执行,而是接收到一个数组:
3> func square(_ x: Int) throws -> Int {
4. return x * x
5. }
6> let squares = try numbers.lazy.map(square)
squares: [Int] = 5 values {
[0] = 1
[1] = 4
[2] = 9
[3] = 16
[4] = 25
}
为什么会这样,以及我如何使用抛出闭包惰性地映射一个值数组?
解决方法是
extension LazySequennce {
func tryMap<U>(_ transform: @escaping (Self.Element) throws -> U) -> LazyMapSequence<Self.Elements, Result<U, Error>> {
self.map { x in Result(catching: { try transform(x) }) }
}
}
注意,序列的元素类型是Result<U, Error>
。我们本质上";捕获";抛出any时的错误。必须捕获错误,因为在任何Sequence
上迭代时,协议都要求不抛出错误。
至于map(square)
为什么不懒惰,这正是你所观察到的。LazySequenceProtocol.map
接受一个不抛出的闭包。
func map<U>(_ transform: @escaping (Self.Element) -> U)
-> LazyMapSequence<Self.Elements, U>
当您传入抛出方法时,它会调用Sequence.map
:
func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]
这不是懒惰。
如果有一种看起来像的方法,这一切都会得到解决
func tryMap<U>(_ transform: @escaping (Self.Element) throws -> U)
-> LazyThrowingMapSequence<Self.Elements, U>
然而,这样的LazyThrowingMapSequence
类型不能符合Sequence
,因为它的迭代器不能符合IteratorProtocol
。其迭代器的next
方法抛出,但IteratorProtocol
要求next
不抛出。
理论上可以通过将CCD_ 15添加到CCD_ 16的几个位置来写入CCD_。(LazyMapSequence
的源代码在这里)但使用它会很痛苦,因为你不能用for
循环来迭代它,而且它没有Sequence
协议中任何方便的方法。