代码之家  ›  专栏  ›  技术社区  ›  matt

Swift Array()强制不明确,没有更多上下文,但仅在扩展中

  •  6
  • matt  · 技术社区  · 6 年前

    这样说是合法的( 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())
        }
    }
    

    但为什么要这么做呢?(对吗?)

    1 回复  |  直到 6 年前
        1
  •  5
  •   Hamish    6 年前

    这是一个已知的错误( 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.
    }
    

    这很方便,但你遇到的错误是,斯威夫特会 总是 即使是不正确的,也要做出这样的推断。

    所以,在你的例子中:

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

    斯威夫特将代码解释为 let arrenum = Array<Element>(self.enumerated()) ,就像你在 Array<Element> . 这是不正确的,因为 enumerated() 产生Swift应该推断的偏移元素元组对序列 Array 成为 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并没有对完全限定的类型做同样的推断(我不确定你是否应该依赖这个事实)。

    最后值得注意的是 阵列 的初始化程序,您可以使用 map(_:) 相反,为了完全避免这个问题:

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

    它和initialiser调用一样,将返回一个偏移元素对数组。