为啥 Swift 语言指南建议使用 Int “即使已知值是非负的”?
Posted
技术标签:
【中文标题】为啥 Swift 语言指南建议使用 Int “即使已知值是非负的”?【英文标题】:Why does the Swift language guide suggest using Int "even when values are known to be non-negative"?为什么 Swift 语言指南建议使用 Int “即使已知值是非负的”? 【发布时间】:2014-08-02 13:20:21 【问题描述】:这是一个关于 Swift 编程风格的问题,特别是 Int
与 UInt
。
Swift 编程语言指南建议程序员使用通用有符号整数类型Int
,即使已知变量为非负数也是如此。来自the guide:
仅当您特别需要与平台的本机字长相同大小的无符号整数类型时才使用 UInt。如果不是这种情况,则首选 Int,即使要存储的值已知为非负数。对整数值一致使用 Int 有助于代码互操作性,避免在不同数字类型之间进行转换,并匹配整数类型推断,如类型安全和类型推断中所述。
但是,UInt
在 32 位架构上是 32 位无符号的,而在 64 位架构上是 64 位无符号的,因此使用 Int
而不是 UInt
没有性能优势。
相比之下,Swift 指南给出了一个后面的例子:
让年龄 = -3 assert(age >= 0, "一个人的年龄不能小于零") // 这会触发断言,因为年龄不是 >= 0
这里,运行时问题可能会在编译时被发现,如果代码被写成:
let age:UInt = -3
// this causes a compiler error because -3 is negative
还有许多其他情况(例如任何将索引集合的东西)使用UInt
会在编译时而不是运行时发现问题。
所以问题是:Swift 编程语言指南中的建议是否合理,并且使用Int
的好处“即使已知要存储的值是非负数”超过使用 @ 的安全优势987654331@?
附加说明: 使用 Swift 几个星期后,很明显需要与 Cocoa UInt
进行互操作。例如,AVFoundation
框架在任何需要“计数”的地方使用无符号整数(样本数/帧数/通道数等)。将这些值转换为Int
可能会导致值大于Int.max
的严重错误
【问题讨论】:
这当然取决于你认为什么重要。我倾向于同意文档,它只是使代码更易于使用int
@JackJames 我同意这是个人开发人员的优先级和正在处理的代码的问题。我没有看到任何令人信服的案例,这让我认为 Apple 不应该建议人们不要使用 UInt,因为严格坚持使用 Int 可能会导致代码以各种令人讨厌的方式中断。
在 C 中不鼓励使用无符号整数的传统原因是向下计数的 for
循环很容易出错;例如for (unsigned a = 10; a > 0; --a)
是错误的,因为根据定义,a
总是 > 0。
同意杰克和杰米的观点。将 UInt 用于已知的非负值会将意图和语义信息传达给下一个阅读代码的开发人员。如果您优先考虑互操作性,那么您可能会选择 Int。
@alastair unsigned a
并不总是 > 0 它是 >= 0
【参考方案1】:
它在你的问题中说.. “对整数值始终使用 Int 有助于代码互操作性,避免在不同数字类型之间进行转换,并匹配整数类型推断,如类型安全和类型推断中所述。”
这避免了诸如将 Int 分配给 UInt 之类的问题。分配给 UInts 的负 Int 值会产生较大的值,而不是预期的负值。两者的二进制表示不区分一种类型与另一种类型。
另外,两者都是类,一个不是另一个的后代。构建接收 Ints 的类在没有重载的情况下无法接收 UInt,这意味着当大多数框架接收 Ints 时,两者之间的转换将是 UInt 的常见任务。两者之间的转换也可以成为一项不平凡的任务。
前两段谈到“互操作性”和“不同数字类型之间的转换”。如果不使用 UInts 可以避免的问题。
【讨论】:
对,所以这实际上是关于与 Swift 框架的互操作性。我仍然认为一般来说对已知的非负值使用无符号整数更安全,但我同意对于每种类型的所有可能值,两种类型之间没有合理的转换。因此,如果互操作性优于安全性,那么我理解在可能的情况下使用 Int 的设计选择。【参考方案2】:我认为使用 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
s,您可以添加代码来检查您的条件,而不是崩溃:
if a.aboveZero > 0
//Do your thing
else
//Handle bad data
我什至可以将他们反对使用 UInt
s 的建议等同于反对使用隐式展开的选项的建议:不要这样做,除非你确定你不会得到任何否定,否则你'会出现运行时错误(最简单的情况除外)。
【讨论】:
您可以很容易地为UInt
案例添加这些检查;你只需要检查num
和a.aboveZero
是>= 10
。
另外,您可以使用 num &- 10 禁用运行时溢出检查。以上是关于为啥 Swift 语言指南建议使用 Int “即使已知值是非负的”?的主要内容,如果未能解决你的问题,请参考以下文章