问题描述
这是合法的说法(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<Element>(self.enumerated())
,就像您在Array<Element>
正文中一样.这是不正确的,因为enumerated()
会产生一系列偏移元素元组对– Swift应该将Array
推断为Array<(offset: Int, element: 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()强制模棱两可,没有更多上下文,但仅在扩展中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!