为什么 Swift 语言指南建议使用 Int "even when values are known to be non-negative"?



这是一个关于Swift编程风格的问题,特别是IntUInt

Swift编程语言指南建议程序员使用通用的有符号整数类型Int,即使已知变量是非负的。来自指南:

只有当你特别需要一个与平台原生字长相同大小的无符号整数类型时才使用UInt。如果不是这种情况,则首选Int,即使已知要存储的值是非负的。整数值一致地使用Int有助于代码互操作性,避免在不同数字类型之间转换的需要,并匹配整数类型推断,如类型安全和类型推断所述。

然而,UInt在32位架构上是32位无符号的,在64位架构上是64位无符号的,所以使用IntUInt没有性能上的好处。

相比之下,Swift指南给出了一个后面的例子:

let age = -3
assert(age>= 0, "一个人的年龄不能小于0 ")
//这会触发断言,因为age不是>= 0

在这里,如果代码写成

,则可以在编译时捕获运行时问题:
let age:UInt = -3  
// this causes a compiler error because -3 is negative

还有许多其他情况(例如任何将索引集合的情况),使用UInt将在编译时而不是运行时捕获问题。

所以问题是:Swift编程语言指南中的建议是否合理,使用Int的好处"即使要存储的值已知是非负的"是否超过使用UInt的安全优势?

附加说明:使用Swift几周后,现在很明显,要与Cocoa UInt互操作性是必需的。例如,AVFoundation框架在任何需要"计数"的地方使用无符号整数(采样/帧/通道等的数量)。如果这些值大于Int.max

,则将这些值转换为Int可能会导致严重的错误。

我认为使用UInt并不像你想象的那么安全。如你所述:

let age:UInt = -3

导致编译器错误。我也试过:

let myAge:Int = 1
let age:UInt = UInt(myAge) - 3

也会导致编译器错误。然而,以下(我认为在实际程序中更常见)场景没有编译错误,但实际上导致EXC_BAD_INSTRUCTION的运行时错误:

func sub10(num: Int) -> UInt {
    return UInt(num - 10) //Runtime error when num < 10
}
sub10(4)

以及:

class A {
    var aboveZero:UInt
    init() { aboveZero = 1 }
}
let a = A()
a.aboveZero = a.aboveZero - 10 //Runtime error

如果这些是普通的Int,而不是崩溃,您可以添加代码来检查您的条件:

if a.aboveZero > 0 {
    //Do your thing
} else {
    //Handle bad data
}

我甚至可以把他们反对使用UInt s的建议等同于反对使用隐式解包装可选选项的建议:除非你确定你不会得到任何否定,否则不要这样做,因为否则你会得到运行时错误(除了最简单的情况)

你的问题里说…整数值一致使用Int有助于代码互操作性,避免在不同数字类型之间转换的需要,并匹配整数类型推断,如类型安全和类型推断中所述。

这避免了将Int型赋值给UInt型等问题。赋给Int的负Int值会产生较大的值,而不是预期的负值。两者的二进制表示不能区分一种类型和另一种类型。

同样,两者都是类,一个不是从另一个派生的。在没有重载的情况下,接收int的类不能接收int,这意味着当大多数框架接收int时,在两者之间进行转换将是使用int的常见任务。两者之间的转换也会成为一项非常重要的任务。

前两段提到了"互操作性"one_answers"不同数字类型之间的转换"。如果不使用单元可以避免的问题

最新更新