奇怪的斯威夫特数字类型铸造

Eug*_*nok 12 casting type-inference swift

我刚刚注意到Swift对Int和Double进行了一些类型的转换.当我尝试评估时

(10 / 3.0) - (10 / 3)
Run Code Online (Sandbox Code Playgroud)

0.333...预计,但实际上0.0.有人可以解释一下吗?

Mar*_*n R 17

是的,我也发现这非常令人惊讶.Double符合两者FloatLiteralConvertibleIntegerLiteralConvertible(ExpressibleByFloatLiteralExpressibleByIntegerLiteralSwift 3).因此,Double可以使用浮点字面值初始化a

let a = 3.0
Run Code Online (Sandbox Code Playgroud)

或者使用整数文字:

let b : Double = 10
Run Code Online (Sandbox Code Playgroud)

(对于像Float和 等的其他浮点类型也是如此CGFloat.)

现在,对于我们所有具有(Objective-)C背景的人来说,这两种说法都可能出乎意料

let x : Double = 10/4     // x = 2.5 .  Really? Yes!
let y = 10/4 as Double    // Same here ...
Run Code Online (Sandbox Code Playgroud)

将值0.25赋给变量.从上下文来看,除法的结果必须是a Double并且Swift不会隐式转换类型.因此/ 必须是浮点除法运算符

func /(lhs: Double, rhs: Double) -> Double
Run Code Online (Sandbox Code Playgroud)

所以编译器Double从文字"10"和"4" 创建两个参数.(如果10/4被视为两个整数的除法,那么结果也将是一个整数,并且不能分配给Double.)

请注意,这与...不同

let z = Double(10/4)   // z = 2.0 . (I just thought that I understood it &%$!?)
Run Code Online (Sandbox Code Playgroud)

它执行整数除法并将结果转换为Double. Double有一个init(_ v: Int)构造函数,因此10/4 可以将其视为两个整数的除法.

如果我们总结这些结果,这看起来有点奇怪:

let x : Double = 10/4     // x = 2.5 
let y = 10/4 as Double    // y = 2.5
let z = Double(10/4)      // z = 2.0
Run Code Online (Sandbox Code Playgroud)

现在我们可以将这些结果应用于您的表达式

(10 / 3.0) - (10 / 3)
Run Code Online (Sandbox Code Playgroud)

第一部分(10 / 3.0)只能是a Double,因此- 必须是浮点减法运算符

func -(lhs: Double, rhs: Double) -> Double
Run Code Online (Sandbox Code Playgroud)

因此(10 / 3)也必须是一个Double.再次,/必须是浮点除法运算符,因此103被视为Double常数.

因此表达式相当于

(Double(10) / 3.0) - (Double(10) / Double(3))
Run Code Online (Sandbox Code Playgroud)

并评估为0.0.如果将表达式更改为

(10 / 3.0) - Double(10 / 3)
Run Code Online (Sandbox Code Playgroud)

那么结果是0.333...因为在这种情况下,10 / 3 是两个整数常数的除法,如上所述.

  • 很棒的解释! (3认同)