[英]Lazily Mapping an Array Using a Throwing Closure
当延迟映射值数组时,我按预期收到类型为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
}
这是为什么,我如何使用抛出闭包懒惰地 map 值数组?
解决方法是
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>
。 无论何时抛出任何错误,我们基本上都会“捕获”错误。 必须捕获错误,因为在遍历任何Sequence
时,协议要求不抛出任何错误。
至于为什么map(square)
不偷懒,正如你观察到的那样。 LazySequenceProtocol.map
采用不抛出的闭包。
func map<U>(_ transform: @escaping (Self.Element) -> U)
-> LazyMapSequence<Self.Elements, U>
当您传入 throwing 方法时,它会调用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
不抛出。
理论上可以通过在LazyThrowingMapSequence
的几个地方添加throws
来编写LazyMapSequence
。 ( LazyMapSequence
的源代码在这里)但是使用它会很痛苦,因为你不能用for
循环迭代它,而且它没有Sequence
协议中的任何方便方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.