'lazy' 的使用不明确
Ambiguous use of 'lazy'
我不知道为什么 this example 是模棱两可的。 (我很抱歉没有在这里添加代码,它太长了。)
我已将 prefix (_ maxLength)
作为重载添加到 LazyDropWhileBidirectionalCollection
。 subscript(position)
是在 LazyPrefixCollection
上定义的。然而,上面示例中的以下代码不应该有歧义,但它是:
print([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2)[0]) // Ambiguous use of 'lazy'
据我了解,将使用协议层次结构中更高层的重载。
根据编译器,它不能在两种类型之间进行选择;即 LazyRandomAccessCollection
和 LazySequence
。 (这没有意义,因为 subscript(position)
不是 LazySequence
的方法。)LazyRandomAccessCollection
是这里合乎逻辑的选择。
如果我删除下标,它会起作用:
print(Array([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2))) // [0, 1]
可能是什么问题?
将最后一行更改为:
let x = [0, 1, 2]
let lazyX: LazySequence = x.lazy
let lazyX2: LazyRandomAccessCollection = x.lazy
let lazyX3: LazyBidirectionalCollection = x.lazy
let lazyX4: LazyCollection = x.lazy
print(lazyX.drop(while: {_ in false}).prefix(2)[0])
您会注意到数组有 4 种不同的惰性构造 - 您必须明确。
这里的踪迹太过复杂和模糊。您可以通过删除元素来查看。特别是去掉最后一个下标:
let z = [0, 1, 2].lazy.drop(while: {_ in false}).prefix(2)
在此配置中,编译器希望将 z
键入为 LazyPrefixCollection<LazyDropWhileBidirectionalCollection<[Int]>>
。但这不能用整数索引。 我知道它应该是这样,但当前的编译器无法证明它。(见下文)所以你的 [0]
失败了。而且回溯还不够强大,无法退出这个疯狂的迷宫。不同 return 类型的重载太多了,编译器不知道你想要哪一种。
但是这个特殊情况很容易修复:
print([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2).first!)
就是说,我绝对会避免这么用力地推动编译器。这对今天的 Swift 来说太聪明了。特别是 return 不同类型的重载在 Swift 中通常不是一个好主意。当它们很简单时,是的,你可以摆脱它。但是当你开始对它们进行分层时,编译器没有足够强大的证明引擎来解决它。 (也就是说,如果我们研究了足够长的时间,我敢打赌它实际上在某种程度上是模棱两可的,但诊断具有误导性。当你变得过于聪明时,这是一种非常常见的情况 Swift。)
既然你描述了它(在评论中),推理就很简单了。
LazyDropWhileCollection
不能有整数索引。索引下标必须是 O(1)。这就是 Index
下标与其他下标的含义。 (Index
下标还必须 return Element
类型,否则会崩溃;它不能 return 和 Element?
。这就是 DictionaryIndex
与 Key
不同。)
由于集合是惰性的并且有任意数量的缺失元素,查找任何特定整数 "count"(第一个、第二个等)是 O(n)。如果不遍历至少 100 个元素,就不可能知道第 100 个元素是什么。要成为一个集合,它的 O(1) 索引必须采用一种只能通过先前遍历序列来创建的形式。不能是 Int
.
这很重要,因为当您编写如下代码时:
for i in 1...1000 { print(xs[i]) }
你希望它是 1000 的数量级 "steps," 但如果这个集合有一个整数索引,它将是 100 万步的数量级。通过包装索引,它们可以防止您首先编写该代码。
这在像 Swift 这样的高度通用语言中尤其重要,在这种语言中,通用算法层可以轻松地将意外的 O(n) 操作级联成完全不可行的性能("unworkable" 我的意思是您预计需要花费几分钟或更长时间的毫秒数。
我不知道为什么 this example 是模棱两可的。 (我很抱歉没有在这里添加代码,它太长了。)
我已将 prefix (_ maxLength)
作为重载添加到 LazyDropWhileBidirectionalCollection
。 subscript(position)
是在 LazyPrefixCollection
上定义的。然而,上面示例中的以下代码不应该有歧义,但它是:
print([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2)[0]) // Ambiguous use of 'lazy'
据我了解,将使用协议层次结构中更高层的重载。
根据编译器,它不能在两种类型之间进行选择;即 LazyRandomAccessCollection
和 LazySequence
。 (这没有意义,因为 subscript(position)
不是 LazySequence
的方法。)LazyRandomAccessCollection
是这里合乎逻辑的选择。
如果我删除下标,它会起作用:
print(Array([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2))) // [0, 1]
可能是什么问题?
将最后一行更改为:
let x = [0, 1, 2]
let lazyX: LazySequence = x.lazy
let lazyX2: LazyRandomAccessCollection = x.lazy
let lazyX3: LazyBidirectionalCollection = x.lazy
let lazyX4: LazyCollection = x.lazy
print(lazyX.drop(while: {_ in false}).prefix(2)[0])
您会注意到数组有 4 种不同的惰性构造 - 您必须明确。
这里的踪迹太过复杂和模糊。您可以通过删除元素来查看。特别是去掉最后一个下标:
let z = [0, 1, 2].lazy.drop(while: {_ in false}).prefix(2)
在此配置中,编译器希望将 z
键入为 LazyPrefixCollection<LazyDropWhileBidirectionalCollection<[Int]>>
。但这不能用整数索引。 我知道它应该是这样,但当前的编译器无法证明它。(见下文)所以你的 [0]
失败了。而且回溯还不够强大,无法退出这个疯狂的迷宫。不同 return 类型的重载太多了,编译器不知道你想要哪一种。
但是这个特殊情况很容易修复:
print([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2).first!)
就是说,我绝对会避免这么用力地推动编译器。这对今天的 Swift 来说太聪明了。特别是 return 不同类型的重载在 Swift 中通常不是一个好主意。当它们很简单时,是的,你可以摆脱它。但是当你开始对它们进行分层时,编译器没有足够强大的证明引擎来解决它。 (也就是说,如果我们研究了足够长的时间,我敢打赌它实际上在某种程度上是模棱两可的,但诊断具有误导性。当你变得过于聪明时,这是一种非常常见的情况 Swift。)
既然你描述了它(在评论中),推理就很简单了。
LazyDropWhileCollection
不能有整数索引。索引下标必须是 O(1)。这就是 Index
下标与其他下标的含义。 (Index
下标还必须 return Element
类型,否则会崩溃;它不能 return 和 Element?
。这就是 DictionaryIndex
与 Key
不同。)
由于集合是惰性的并且有任意数量的缺失元素,查找任何特定整数 "count"(第一个、第二个等)是 O(n)。如果不遍历至少 100 个元素,就不可能知道第 100 个元素是什么。要成为一个集合,它的 O(1) 索引必须采用一种只能通过先前遍历序列来创建的形式。不能是 Int
.
这很重要,因为当您编写如下代码时:
for i in 1...1000 { print(xs[i]) }
你希望它是 1000 的数量级 "steps," 但如果这个集合有一个整数索引,它将是 100 万步的数量级。通过包装索引,它们可以防止您首先编写该代码。
这在像 Swift 这样的高度通用语言中尤其重要,在这种语言中,通用算法层可以轻松地将意外的 O(n) 操作级联成完全不可行的性能("unworkable" 我的意思是您预计需要花费几分钟或更长时间的毫秒数。