用常量变量替换常量文字值时,如果没有更多上下文,表达式的类型将不明确



我想知道,修复以下编译器错误的好方法是什么?

class A {
var x: Int32

init() {
x = -1
}
}
let a: A? = nil
// No issue.
let ok: Int = Int(a?.x ?? -1)
// Type of expression is ambiguous without more context
let CONSTANT: Int = -1
let not_ok: Int = Int(a?.x ?? CONSTANT)

如果我们使用CONSTANT而不是-1,那么为什么我们得到表达式类型在没有更多上下文的情况下是不明确的

什么是修复编译器错误的好方法(保留相同的类、相同的类型和相同的CONSTANT(,但仍然保留1行?

你可以这么说也是出于同样的原因:

let d = 3.0
let d2 = d + 1

但不是这个:

let i = 1
let d3 = d + i

Swift会将文本1强制转换为所需的数字类型(此处为Double(,但不会从其类型中强制转换变量

所以答案是:使类型匹配。

??运算符的声明如下:

func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
rethrows -> T

在表达式Int(a?.x ?? -1)中,编译器需要为
??运算符推断T。它成功地推断出T == Int32,因为

  • 表达式CCD_ 10具有类型CCD_
  • ??可以在这里返回Int32,因为Int有一个取Int32的初始化器
  • 最相关的是,文字-1可以转换为Int32,因为Int32符合ExpressibleByIntegerLiteral

但是,如果您改为执行Int(a?.x ?? CONSTANT),那么最后一点将不起作用。ExpressibleByIntegerLiteral仅适用于文字,而不是任何常量。编译器将CONSTANT视为Int类型的表达式,并非常努力地为表达式a?.x ?? CONSTANT找到一个类型,但它找不到,并抛出一条不太有用的错误消息。

我认为错误消息不是很有用,因为在这种情况下,它需要考虑很多事情(返回类型、两个参数、Int.init的过载解决方案(,而且可能很难准确指出哪里出了问题。

无论如何,要解决这个问题,您只需将常数转换为Int32:

Int(a?.x ?? Int32(CONSTANT))

或者,如果您不想将CONSTANT转换为Int32,然后再转换回Int,您可以将其重写为:

a.map { Int($0.x) } ?? CONSTANT

"如果a不为零,则将a映射到其x作为Int,否则CONSTANT〃;。

最新更新