“不可变”优先
不可变(Immutable)指的是在变量赋值或对象创建结束之后,使用者就不能再改变它的值或状态。不可变意味着只读不写,因此不可变对象天然地具备线程安全的特性,即如无其它特殊限制的话可以在任何线程上自由调用。此外,相较于可变对象,不可变对象的访问没有副作用,因此在一些场合下也会让程序更易于了解,而且提供较高的安全性。
不可变通常可以分为两种,一种是不可变变量,不可变变量是指经初始化后其值就不可被修改的变量;另一种是不可变类型,不可变类型是指在构造完成后实际数据对象的内容无法被改变。
在仓颉中,let 定义的变量是不可变变量,而像 String、enum 等类型是不可变类型,这些都是不可变思想在仓颉中的应用。更多地使用不可变特性可以让程序更安全,也更利于理解和维护。
函数参数不可变
在仓颉中,所有函数形参都是不可变的,这意味着我们无法对形参赋值,如果形参是值类型,也无法修改形参的成员。
struct Point {
var x: Int
var y: Int
init(x: Int, y: Int) { ... }
...
}
func f(a: Point) { // a 不可变
a = Point(0, 0) // error
a.x = 2 // error
}
模式匹配引入的新变量不可变
在仓颉中,模式匹配支持变量绑定模式,我们可以将目标值解析到新绑定的变量中,但这个变量仍然是不可变的。这意味着我们无法对绑定的变量赋值,如果变量是值类型,也无法修改变量的成员。
func f(a: ?Point) {
match (a) {
case Some(b) => //b 不可变
b = Point(0, 0) // error
b.x = 2 // error
case None => ()
}
}
闭包捕获可变变量不允许逃逸
在仓颉中,闭包指的自包含的函数或 lambda,闭包可以从定义它的静态作用域中捕获变量,即使对闭包调用不在定义的作用域,仍可以访问其捕获的变量。
仓颉中允许闭包捕获可变变量,但不允许该闭包继续逃逸,这避免了对可变变量修改可能导致的意外行为。
func f() {
let a = 1
var b = 2
func g() {
print(a) // ok
print(b) // ok
}
return g // error, g 捕获了可变变量 b,g 不允许作为表达式使用。
}