代码缺陷
从软件开发的角度来看,一个软件系统想要提供具有良好用户体验的功能,最基本的要求就是控制缺陷。
为了控制缺陷,在软件工程中,定义了各种各样的流程,从代码的格式,到 linting ,到 code review ,再到单元测试、集成测试、手工测试。

语法缺陷
这个缺陷,大部分编程语言会在开发时,给到详尽的提示,语法错误出现在哪里。
类型安全缺陷
类型安全缺陷需要语言本身的类型系统协助找出缺陷。
内存安全缺陷
几乎所有的语言都有内存安全问题。
对于内存自动管理的语言,自动管理机制可以帮助解决大部分内存问题,不会出现内存使用了没有释放、使用了已释放内存、使用了悬停指针等情况。如 Java / Python / Golang / Elixir 等,它们通过语言的运行时解决了内存安全问题。
但这只是大部分被解决了,还有比如逻辑上存在的内存泄漏问题;一个带 TTL 的缓存,没设计好,表中的内容超时后没有删除,会导致内存使用一直增长。这种因为设计缺陷导致的内存泄漏,所有语言都没能够解决这个问题,只能说尽可能地解决。
资源安全缺陷
资源安全缺陷也是大部分语言都会有的问题。
诸如文件 /socket 这样的资源,如果分配后没有很好地释放,就会带来资源的泄露,支持 GC 的语言对此也无能为力,很多时候只能靠程序员手工释放。
然而资源的释放并不简单,尤其是在做异常处理或者非正常流程的时候,很容易忘记要释放已经分配的资源。
Rust 可以说基本上解决了主要的内存和资源的安全问题,通过所有权、借用检查和生命周期检查,来保证内存和资源一旦被分配,在其生命周期结束时,会被释放。
并发安全缺陷
并发安全缺陷发生在支持多线程的语言中,比如两个线程间访问同一个变量,如果没有做合适的临界区保护,就很容易发生并发安全问题。
Rust 通过所有权规则和类型系统,主要是两个 trait :Send / Sync 来解决这个问题。
很多高级语言会把线程概念屏蔽掉,只允许开发者使用语言提供的运行时来保证并发安全。比如 Golang 要使用 channel 和 Goroutine ,Erlang 只能用 Erlang process ,只要在它提供的框架下,并发处理就是安全的。
这样可以处理绝大多数并发场景,但遇到某些情况就容易导致效率不高,甚至阻塞其它并发任务。比如当有一个长时间运行的 CPU 密集型任务,使用单独的线程来处理要好得多。
处理并发有很多手段,但是大部分语言为了并发安全,把不少手段都屏蔽了,开发者无法接触到,但是 Rust 都提供了,同时还提供了很好的并发安全暴涨,可以在合适的场景,安全地使用合适的工具。
错误处理缺陷
错误处理作为代码的一个分支,会占到代码量的 30% 甚至更多。在实际工程中,函数频繁嵌套的时候,整个过程会变得非常复杂,一旦处理不好就会引入缺陷。常见的问题是系统出错了,但抛出的错误并没有得到处理,导致程序在后续的运行中崩溃。
很多语言并没有强制开发者一定要处理错误,Rust 使用 Result<T, E> 类型来保证错误的类型安全,还强制必须处理这个类型返回的值,避免开发者丢弃错误。
代码风格和常见错误引发的缺陷
很多语言都会提供代码格式化工具和 linter 来消灭这类缺陷。Rust 有内置的 cargo fmt 和 cargo clippy 帮助开发者统一代码风格,避免常见的开发错误。
逻辑缺陷、功能缺陷、用户体验缺陷是语言和编译期无法帮助解决的。
- 对于逻辑缺陷,需要有不错的单元测试覆盖率
- 对于功能缺陷,需要通过足够好的集成测试,把用户主要使用的功能测试一遍
- 对于用户体验缺陷,需要端到端的测试,甚至手工测试,才能发现
小结
从上述介绍中,Rust 把尽可能多的缺陷扼杀在摇篮中。Rust 在编译时解决掉的很多缺陷,如资源释放安全、并发安全和错误处理方面的缺陷,在其他大多数语言中并没有完整的解决方案。
Rust 这门语言,让开发者的时间和精力都尽可能的放在对逻辑、功能、用户体验缺陷的优化上。
Ayingotts's notes