0%

从一些细节谈谈为什么说 Swift 是一门更安全的语言

学习 Swift 的过程中,发现这门新语言在设计上确实融入了很多思考,Swift 宣称相对 Objective-C 是一门更安全的语言,那么本文就从语法设计上,举几个小例子谈谈 Swift 为了安全都做了哪些努力。

Swift 中不允许溢出错误

在 Objective-C 中,如下代码会警告但是可以编译通过,打印结果为 -128,理解进制的就会知道,因为发生了溢出(int8_t 只能保存 -128 到 127 的整数),127 在二进制层面加 1 的结果就是 -128。

1
2
int8_t aInt8 = 128;
NSLog(@"%d", aInt8); // -128

溢出在 C 语言以及 Objective-C 中都是被允许的,但是潜在的 Bug 也会因此产生,大部分开发中我们其实更希望这种情况被及时提醒而不是编译通过,最终给我们一个莫名其妙的值。这种 Bug 往往也难以寻找。

而在 Swift 中,溢出是在语法检查的时候就无法编译通过的,如下面代码:

1
let aInt8: Int8 = 128 // 错误信息:Integer literal '128' overflows when stored into 'Int8'

Swift 不提供隐式的类型转换

与 Objective-C 不同,Swift 是一门强类型语言,我们甚至无法给一个整型变量赋值一个小数,更别说像 Objective-C 那样任意指针指向任意对象了。但是我们不必在所有情况下显式声明变量类型,是因为 Swift 为我们提供了 类型推断(Type Inference),如下面代码:

1
let aDouble = 1.5 // 类型推断为 Double 类型

但是在类型转换上,Swift 要求极为严格,一个 Int 类型绝对是无法和一个 Double 类型相加的,必须显式地类型转换:

1
2
3
4
5
let x: Double = 1.2
let y: Int = 5

// 必须显式进行类型转换,避免潜在 Bug 出现
let sum = Int(x) + y

赋值运算取消返回值

我们看下面代码:

1
2
3
4
5
NSString *aString = nil;

if (aString == nil) {
NSLog(@"aString is nil."); // 打印 aString is nil.
}

这段代码本身没有意义,目的在于说明一个程序员可能发生的错误,这就是不小心把 == 写成了 =,结果会截然不同,但是 Bug 同样难以寻找。因此在有的 Objective-C 代码规范中会有这样的规定,建议上面代码中的 condition 部分写成 nil == aString 以避免类似 Bug 的发生。

而在 Swift 中,首先是没有非 0 即真的概念的(Swift 认为,0 应该是和其他整数一样的,不应该用它来表示空,因此发明了可选型),其次,赋值运算是没有返回值的,这样把它放在 if 语句中就直接会报错。

for-in、if-else、switch 等语句中的大括号不可省略

记得听过一个故事,苹果的一位程序员因为 if 语句只有一句代码所以没有加大括号,后期添加代码时仍然忘记添加,因此导致 Bug。Swift 中所有这些语句均必须添加大括号。

结尾

本文只是从一些小细节入手去谈 Swift 的安全性,其更多地安全性的表现应该是强类型可选型等等,这些内容值得单独去讲,之后会专门写文章去理解相关的概念。