一尘不染

Swift Array()强制模棱两可,没有更多上下文,但仅在扩展中

swift

可以这样说(arr是一个数组):

let arrenum = Array(arr.enumerated())

那么为什么这样说不合法?

extension Array {
    func f() {
        let arrenum = Array(self.enumerated())
        // error: type of expression is ambiguous without more context
    }
}

编辑 似乎这是一种解决方法:

extension Array {
    func f() {
        typealias Tup = (offset:Index, element:Element)
        let arrenum = Array<Tup>(self.enumerated())
    }
}

但是为什么需要那?(对吗?)


阅读 238

收藏
2020-07-07

共1个答案

一尘不染

这是一个已知的错误(SR-1789)。Swift目前具有一项功能,您可以在自己的主体内引用泛型类型,而不必重复其占位符类型-
编译器会为您推断出它们与的类型相同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也会 始终 做出这种推断。

因此,在您的示例中:

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()产生一系列偏移元素元组对–应该推断Array是Swift
Array<(offset: Int, element: Element)>

您已经发现的一种解决方法是显式指定占位符类型,以防止编译器做出这种错误的推断。

extension Array {
  func f() {
    let arrenum = Array<(offset: Int, element: Element)>(self.enumerated())
  }
}

另一个可能的解决方法似乎是使用完全限定的类型,例如:

extension Array {
  func f() {
    let arrenum = Swift.Array(self.enumerated())
  }
}

看来Swift不会对完全限定的类型进行相同的推断(不过我不确定您是否应该依赖这个事实)。

最后,值得注意的是Array,您可以map(_:)代替使用来避免初始化问题,而不必完全调用:

extension Array {
  func f() {
    let arrenum = self.enumerated().map { $0 }
  }
}

就像初始化程序调用一样,它将给您返回一组偏移元素对。

2020-07-07