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