为什么 Rust 里的变量被设计成默认不可变,要加mut
关键词才可变?为什么不设计成默认可变,加关键词变成不可变? 或者两者同等地位,比如像某语言一样let
不可变,var
可变?
默认设计成不可变没啥特别原因,但是可以聚焦到 rust 的基本特性:安全性。从这个方面考虑。如果忘记设置 mut
,编译器会捕捉到错误,并让你知道你已经改变了一些你可能不打算改变的东西。如果默认情况下绑定是可变的,编译器将无法告诉你这一点。若你确实打算改变,那么解决方案很简单:添加mut
。
通常情况下,你可以经常避免显示可变,在 Rust 中这是更可取的,话虽然如此,有时候可变是必要的,所以并不禁止。
Shadowing
不同于将变量标记为 mut
,因为如果我们在不使用 let
关键字的情况下不小心尝试重新分配给该变量,则会出现编译时错误。通过使用 let
,我们可以对一个值执行一些转换,但在这些转换完成后变量是不可变的。
鉴于一种语言具有可变和不可变变量,对我来说默认情况下不可变似乎更好。因为:
当我们谈论语言默认情况时,其实是在说 当你忘记或者懒得在声明变量时指定可变性,将会发生什么? 有两种情况:
当然,未来的程序员可能是你本人,在几个月或者几年后你忘记项目的所有细节,当编译器捕获到错误时你会很开心。
不确定:可能默认情况下不可变的话允许优化,反之则不允许。默认情况下不可变可能带来性能提升。
我怀疑微软有足够的证据表明默认情况下不可变是更好的选择:他们估计 70% 的安全问题都可追溯到此类内存滥用错误:我们需要一种更安全的系统编程语言——微软安全响应中心
简而言之,打个比方,当我出门并打算关闭身后前门时,我更愿意默认情况下它是自动关上了。
rust 允许 variable shadowing
,所以下面这种写法是完全有可能的。
let a = 0u8;
let mut a = a;
a = 1;
let a = a;
用 rust-analyzer 辅助可以看出一个变量有没有被 shadowing
过,但是靠肉眼判断应该是不太行的。
除了 shadowing,还有 interior mutability……感觉 rust 的默认不可变是一种非常宽松的约束,只是类似于提醒、建议的程度,很容易绕开。
Rust 变量默认不可变的设计本意是想将可能出现的错误扼杀在摇篮中(编译器行为),类似提醒和告警等。如果你非要绕还是可以绕过去滴。再完备的法典,不还是有人可以钻到空子么?法律只是最低的道德标准,语言设计理念亦然。