当前位置: 首页 > 面试题库 >

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

金理
2023-03-14
问题内容

可以这样说(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())
    }
}

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


问题答案:

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

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



 类似资料:
  • 我有Python 3.7.5和Python 3.8安装在同一个windows 10机器上。它们都是从python.org/downloads.安装的。当我运行pip安装覆盖(使用最新版本的pip)时,它会在3.7.5下安装带有c扩展的覆盖,在3.8.2下安装不带c扩展的覆盖。 我怎么能强制覆盖安装与c扩展,因为性能是可怕的没有他们? 看起来是3.7。5下载:https://files.python

  • 问题内容: 在Java中,我可以以某种方式强制某个扩展了抽象类的类以将Object作为参数实现其构造函数吗? 就像是 问题答案: 您可以在抽象类中使用带有参数的构造函数(如果要禁止匿名子类,请将其保护)。 这样做会强制实现类具有显式构造函数,因为它必须使用一个参数来调用超级构造函数。 但是,您不能强制覆盖的类具有带有参数的构造函数。它总是可以伪造这样的参数:

  • 问题内容: 我正在为某些目录编写一些脚本,但是这些目录包含各种文件类型。 我想只是和现在,但也许其他几个人的未来。 到目前为止,我有: 谁能告诉我我现在如何只添加特定的文件扩展名? 问题答案: 只需使用参数,如下所示: 那应该做你想要的。 从下面的HoldOffHunger答案中获取解释: :命令 :递归地 :忽略大小写 :所有* .cpp:C ++文件(如果文件名中带有星号的目录,请使用\进行转

  • 我想知道我是否可以强制扩展我的通知,有两个按钮,因为我不认为用户会找到他们,如果他们不展开。 Poweramp似乎做到了这一点,任何人请帮助我。thx提前。

  • 我有一节简单的课 这将输出为10,没有任何错误!!!我原以为这会给我一个ClassCastException,其中有些错误,比如Integer不能转换为HashMap。 出于好奇和愤怒,我尝试了返回值,如下所示

  • 但是,当我尝试相同的示例时,通过将Integer更改为Object,代码编译得很好,输出为String 谁能帮助我理解为什么当输出来自其中有字符串的方法时,签名中有对象的方法是必需的。以及类型错误不明确的原因是什么。