Appearance
14.3 小结
内存安全是需要一些代码规范来约束才能实现的。这就好比交通安全是需要交通法规来约束才能实现一样。我们不能因为某个具体的人在某个具体的路段上不能直达目标,不得不绕路而行,而否定整个交通法规的意义。交通法规本身肯定还有值得优化的地方,但它优化的方向应该是让社会平均交通事故率下降,提高社会平均通行效率,不能着眼于特定时间特定位置。NLL 的设计就是朝这个方向前进的。Rust 中的生命周期是一个初学者不易理解的难点,而且也确实存在一些情况损害了语言的表达能力。但我们不应该轻易地否定生命周期这个设计,而是应该做一些更精细的、准确的调整,使它尽可能接近“安全”与“不安全”的那条分界线,不偏不倚,否则宽严皆误。
在 C/C++ 的领域,为了提高软件可靠性而设计的代码规范其实有很多,这些先贤总结出来的 C/C++的设计范式和惯用法是非常有利于提高代码质量、降低安全风险的。但是可惜的是,这些良好的设计范式并不是所有人都能遵守的,就好比大街上总是有人试图抄近路,违反交通规则而导致交通事故一样。这些人不理解一个统一的代码规范对于整个项目代码质量的意义。一旦在项目中掺入了一些带有“坏味道”的代码,那它就不一定在哪天给项目带来一个出其不意的问题,哪怕只是一个简单的赋值、函数调用,都可能触发完全超过预期的结果。
A rule is worthless if it is not enforced。如果规则不能强制执行,那么这个规则就是没有价值的。
因此,C/C++ 的领域内也出现了一大批静态代码检查工具。这些工具可以帮助我们提高代码规范的严肃性和可执行性,从而间接增强代码的可靠程度。但是可惜的是,C/C++ 的静态代码检查工具远称不上完美,它总会有误报或者漏报的情况发生。而 Rust 则在这个方向上更进了一步,保证了 segment fault 这一类内存安全问题,可以在静态代码检查阶段“完整无遗漏”地被检查出来。
Rust 之所以能达到这么好的检查效果,并不是因为设计者发明了什么高深的算法,或者比做 C/C++ 静态检查的人更聪明。主要原因是设计者们“作弊”了,他们直接简化了被研究对象。C/C++ 由于本质上的灵活性太强,使得某些安全问题检查极其难以实现。而 Rust 在设计的时候就一直将这些问题考虑在内,所有的功能都不能影响“内存安全”的设计。
当然,Rust 的这种设计自然就带来了 Rust 独有的新的设计范式。有些 C/C++ 风格的代码在 Rust 里面就很难写出来,但这并不一定意味着“表达能力低”,往往是因为用地道的 Rust 处理同样的问题是另外一种你不熟悉的风格而已。要搞清楚这种 Rust 风格的代码究竟是怎样的,就需要多读高质量的开源的 Rust 代码来培养感觉。