Skip to main content
 首页 » 操作系统

swift之为什么 "0x1000之1"周围的括号会导致编译时错误

2024年01月01日33webabcd

我有这段编译得很好的 Swift 代码:

let someArray = Array(count: 45, repeatedValue: 0) 
let a: UIntMax = 0x00010000 
let b = a + someArray.count 
let c = (b + 0x1000 - 1) / 0x1000 
println("\(someArray.count == c), \(c)") 

但是,我认为如果我确保在将 - 1 添加到 b< 之前将其应用于 0x1000,则溢出的可能性会稍微降低一点(第 4 行),所以我想将其更改为:

let c = (b + (0x1000 - 1)) / 0x1000 

令人惊讶的是,该片段不再编译。我在 println 行收到此错误:

Could not find member convertFromStringInterpolationSegment

发生了什么事?为什么带括号的表达式的行为与未带括号的表达式有任何不同,为什么会产生影响?

请您参考如下方法:

很奇怪。添加这些括号将 c 的类型推断从 Int 更改为 UInt64。这会导致最后一行出错,因为 someArray.count 是一个 Int,您无法比较不同的类型。

我会 (a) 提交错误报告并 (b) 分解表达式。


多看了几眼,现在我想知道为什么第一个版本可以编译。一行一行:

  1. 让一个:UIntMax = 0x00010000

    a 是 UInt64 类型。 (UIntMax 只是一个类型别名。)

  2. 让 b = a + someArray.count

    b 也是 UInt64 类型。 “等等,”你说,“你说过你不能添加 UInt64 和 Int 实例!”在这种情况下,正在使用的 + 运算符是这个:

     func +<T : Strideable>(lhs: T, rhs: T.Stride) -> T 
    

    本例中的 UInt64 实例是 strideable 值,Int 实例与其 Stride 匹配。

  3. 令 c = (b + 0x1000 - 1)/0x1000

    先看括号内的子表达式,+和-的结合性意味着这等价于((b + 0x1000) - 1)。此处编译器选择的 + 运算符是 UInt64 的标准运算符,但是 - 运算符是一个采用两个 Strideable 值并返回它们的 Stride:

     func -<T : Strideable>(lhs: T, rhs: T) -> T.Stride 
    

    这导致整个子表达式的类型为 Int 而不是 UInt64,因此 c 也是一个 Int.

我认为编译器错误发生在选择 - 运算符重载时,因为没有理由不继续将事物评估为 UInt64。