Swift Array() 在没有更多上下文的情况下强制模棱两可——但仅限于扩展 [英] Swift Array() coercion ambiguous without more context — but only in extension
问题描述
这样说是合法的(arr
是一个数组):
It is legal to say this (arr
is an Array):
let arrenum = Array(arr.enumerated())
那为什么这样说不合法?
So why isn't it legal to say this?
extension Array {
func f() {
let arrenum = Array(self.enumerated())
// error: type of expression is ambiguous without more context
}
}
<小时>
编辑这似乎是一种解决方法:
EDIT It seems this is a workaround:
extension Array {
func f() {
typealias Tup = (offset:Index, element:Element)
let arrenum = Array<Tup>(self.enumerated())
}
}
但为什么需要这样做?(对吗?)
But why is that needed? (And is it right?)
推荐答案
这是一个已知错误 (SR-1789).Swift 目前有一个特性,你可以在它自己的主体中引用一个泛型类型,而不必重复它的占位符类型——编译器会为你推断它们与 self
.
This is a known bug (SR-1789). Swift currently has a feature where you can refer to a generic type within its own body without having to repeat its placeholder type(s) – the compiler will infer them for you to be the same as the type of self
.
例如:
struct S<T> {
func foo(_ other: S) { // parameter inferred to be `S<T>`.
let x = S() // `x` inferred to be `S<T>`.
}
}
extension S {
func bar(_ other: S) {} // same in extensions too.
}
这很方便,但您遇到的错误是 Swift 会总是做出这种推断,即使它是不正确的.
This is pretty convenient, but the bug you're running into is the fact that Swift will always make this inference, even if it's incorrect.
因此,在您的示例中:
extension Array {
func f() {
let arrenum = Array(self.enumerated())
// error: type of expression is ambiguous without more context
}
}
Swift 将代码解释为 let arrenum = Array
,因为您在 Array
的主体中.这是不正确的,因为 enumerated()
产生了一系列偏移元素元组对——Swift 应该将 Array
推断为 Array<(offset: Int, element: 元素)>
代替.
Swift interprets the code as let arrenum = Array<Element>(self.enumerated())
, as you're in the body of Array<Element>
. This is incorrect, because enumerated()
yields a sequence of offset-element tuple pairs – Swift should have inferred Array
to be Array<(offset: Int, element: Element)>
instead.
您已经发现的一种解决方法是显式指定占位符类型,以防止编译器进行此错误推断.
One workaround, which you've already discovered, is to explicitly specify the placeholder type in order to prevent the compiler from making this incorrect inference.
extension Array {
func f() {
let arrenum = Array<(offset: Int, element: Element)>(self.enumerated())
}
}
另一种可能的解决方法似乎是使用完全限定类型,例如:
Another possible workaround appears to be using the fully-qualified type, for example:
extension Array {
func f() {
let arrenum = Swift.Array(self.enumerated())
}
}
看起来 Swift 不会对完全限定的类型进行相同的推断(不过我不确定您是否应该依赖这个事实).
as it appears Swift doesn't do the same inference for fully-qualified types (I'm not sure if you should rely on this fact though).
最后值得注意的是,您可以使用 map(_:)
而不是调用 Array
的初始化程序来完全避免该问题:>
Finally it's worth noting that instead of doing a call to Array
's initialiser, you could use map(_:)
instead to avoid the issue entirely:
extension Array {
func f() {
let arrenum = self.enumerated().map { $0 }
}
}
与初始化调用一样,它会返回一个偏移量元素对数组.
which, like the initialiser call, will give you back an array of offset-element pairs.
这篇关于Swift Array() 在没有更多上下文的情况下强制模棱两可——但仅限于扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!