视频教程“KCKCJY”
静态类型和垃圾收集
仓颉是静态类型语言,程序中所有变量和表达式的类型都是在编译期确定的,并且在程序运行过程中不会发生改变。相比动态类型系统,静态类型系统对开发者有更多的约束,但能够在编译期尽量早的发现程序中的错误,提高程序的安全性,同时也让程序的行为更加容易预测,为编译优化提供了更多信息,使能更多的编译优化,提升程序的性能。
垃圾收集(GC)是一种自动内存管理机制,它能够自动识别和回收不再需要使用的对象,将开发者从手工释放内存中解放出来,不仅可以提高开发效率,还能有效避免各种常见内存错误,提升程序的安全性。常用的垃圾收集技术包括 tracing 和引用计数(reference counting,即 RC)。仓颉采用 tracing GC 技术,通过在运行时跟踪对象之间的引用关系,来识别活动对象和垃圾对象。
空引用安全
空引用是指引用类型的值可以为 null。代码存在空引用会引发各种各样潜在的风险,空引用被图灵奖得主 Tony Hoare 称为“价值十亿美元的错误”。
在许多编程语言中,空引用都是最常见的陷阱之一,开发者很容易在未确保非空的情况下访问引用类型的成员,从而引发错误或异常。因为语言类型系统并未给非空引用类型提供任何保障。
空引用安全就是旨在消除代码空引用危险。
仓颉是实现了空引用安全的语言之一。在仓颉中,没有提供 null 值,换句话说,仓颉的引用类型永远是非空的。从而在类型上杜绝了空引用的发生。
值得注意的是,表示一个空值在语义中是十分有用的。在仓颉中,对于任意类型T,都可以有对应的可选类型 Option。具有 Option类型的变量要么对应一个实际的具有T类型的值 v,因此取值为Some(v),要么具有空值,取值为None。
可选类型(Option)是一种 enum 类型,是一个经典的代数数据类型,表示有值或空值两种状态。
| enum Option { Some(T) | None}var a: Option = Some(123)a = None | | ---------------------------------------------------------------------------- |
注意Option和T是两个不同的类型,具有两种类型的值之间不能互相转换 —— 给定一个Option类型的表达式e,我们只有通过模式匹配确定其值为Some(v)时(也就是说其值非空),才可以得到一个T类型的值v。因此,对表达式e的任意有意义的处理,必需伴随着模式匹配和对应的判空操作,从而不可能直接对空值None做解引用,避免了空引用异常。
基于可选类型使用的广泛性,仓颉还为可选类型提供了丰富的语法糖支持。例如可以使用 ?T 来代替 Option,也提供了可选链操作符(?.)来简化成员访问,以及空合并操作符(??)来合并有效值。
| var a: ?Int = Nonea?.toString() // Nonea ?? 123 // 123a = Some(321)a?.toString() // Some("321")a ?? 123 // 321 |
|---|
值类型
值类型是一种具有传递即复制的语义行为的类型,具有值类型的变量,其中保存的是数据自身,而不是指向数据的引用。由于值类型的这种特性,开发者选择性地使用值类型可以使得程序显著减少修改语义,从而让程序变得更可预测、更可靠。
例如最典型的并发安全问题就是在程序不同的线程中传递了同一个可变对象,此时访问这个对象的字段将会造成不可预测的 data race 问题。如果这个对象具备值语义,那么在传递的过程中我们就可以保证它经过了完整的复制,让每个线程对该值的访问都是彼此独立的,从而保证了并发安全。
仓颉原生支持了值类型,除了常见的 Int 类型以外,仓颉也可以使用 struct 来实现用户自定义的值类型。
如下面的例子,Point 正是一个值类型,因此在经过赋值后,a 和 b 已经是两个彼此独立的变量,对 a 的修改不会影响到 b。
| struct Point { var x: Int var y: Int init(x: Int, y: Int) { ... } ...}var a = Point(0, 0)var b = aa.x = 1print(b.x) // 0 |
|---|