Swift Array() 在没有更多上下文的情况下强制模棱两可——但仅限于扩展 [英] Swift Array() coercion ambiguous without more context — but only in extension

查看:23
本文介绍了Swift Array() 在没有更多上下文的情况下强制模棱两可——但仅限于扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这样说是合法的(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(self.enumerated()),因为您在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆