空引用安全

空引用是指引用类型的值可以为 null。代码存在空引用会引发各种各样潜在的风险,空引用被图灵奖得主 Tony Hoare 称为“价值十亿美元的错误”。

在许多编程语言中,空引用都是最常见的陷阱之一,开发者很容易在未确保非空的情况下访问引用类型的成员,从而引发错误或异常。因为语言类型系统并未给非空引用类型提供任何保障。

空引用安全就是旨在消除代码空引用危险。

仓颉是实现了空引用安全的语言之一。在仓颉中,没有提供 null 值,换句话说,仓颉的引用类型永远是非空的。从而在类型上杜绝了空引用的发生。

值得注意的是,表示一个空值在语义中是十分有用的。在仓颉中,对于任意类型T,都可以有对应的可选类型 Option<T>。具有 Option<T>类型的变量要么对应一个实际的具有 T 类型的值 v,因此取值为 Some(v),要么具有空值,取值为 None

可选类型(Option<T>)是一种 enum 类型,是一个经典的代数数据类型,表示有值或空值两种状态。

enum Option<T> {
    Some(T) | None
}

var a: Option<Int> = Some(123)
a = None

注意 Option<T>T 是两个不同的类型,具有两种类型的值之间不能互相转换 —— 给定一个 Option<T> 类型的表达式 e,我们只有通过模式匹配确定其值为 Some(v) 时(也就是说其值非空),才可以得到一个 T 类型的值 v。因此,对表达式 e 的任意有意义的处理,必需伴随着模式匹配和对应的判空操作,从而不可能直接对空值 None 做解引用,避免了空引用异常。

基于可选类型使用的广泛性,仓颉还为可选类型提供了丰富的语法糖支持。例如可以使用 ?T 来代替 Option<T>,也提供了可选链操作符(?.)来简化成员访问,以及空合并操作符(??)来合并有效值。

var a: ?Int = None
a?.toString() // None
a ?? 123 // 123
a = Some(321)
a?.toString() // Some("321")
a ?? 123 // 321