前言

rust作为目前比较受欢迎的新兴语言,能够比较好的兼顾安全性和性能. 我们通过参考资料1来了解rust语言设计和社区的一些理念. 这些理念分为两个部分,一部分是rust语言设计追求的目标,另一部分则是如何成为一个更好的rust社区成员.

通过学习rust的设计理念,对于深入掌握rust语言也有所助益.

Rust的设计目标

rust希望赋予开发者构建可靠高效软件的能力.在不冲突的情况下,当然希望可以同时满足以下所有设计目标.在不得不取舍时,从上到下,优先级依次递减.


Reliable(可靠性)

if it compiles, it works

rust希望当程序通过编译后,就可以正确地运行. 这样你可以做较大范围的重构,而不用担心正确性. 类似地,当你使用并发编程或者其他高级特性时,当通过编译后程序就应该正确地运行, 而不是需要各种fuzz测试或者静态动态检查来保证程序的正确性.

C/C++类的语言由于天然的内存不安全特性,在大型项目开发过程中,往往需要大量的额外检查来保证其正确性,这其实带来了相当大的负担.而类似Python这样的解释型语言在运行前,则根本无法保证其正确性.

rust将检查和规则一部分前移到了编译期,另一部分则通过和开发者的约定来完成.这带来的一个后果就是开发者的学习成本和第一次开发成本会有增加,但是长期来看,心智负担和维护成本则更小.

回到语言层面,类型安全强制考虑所有场景是保证可靠性的主要手段.

类型安全

rust在编译时保证了不会出现segment fault,数据竞争,越界访问,UAF等等内存问题.对rust设计者而言,不会接受几乎安全的API.因此安全性可靠性是rust的第一设计原则.

也有些特殊情况需要额外考虑,比如对于数组越界的检查,如果要放在编译期则会大幅增加类型系统的程度,因此对于部分场景rust是放在运行期检查的.

同时,rust允许开发者通过unsafe关键字来避开类型系统检查,以提高开发效率.当使用unsafe时,开发者需要由自己来保证其安全性.

考虑所有可能性

match是一个例子,rust会强制要求开发者处理所有的可能性.

另一个例子则是error的处理,在支持exception的语言中,异常往往可以越过很多中间函数在比较上层捕获,从而掩盖了很多细节.而rust则要求开发者必须直接处理API返回的错误(Result类型**.而为了提高开发效率,又额外提供了?符号,用于快速向上继续返回错误.

总而言之,rust要求错误在整个调用链中都必须是可见的.


Performant(性能)

idiomatic code runs efficiently

rust语言特性经过了精心地优化,一些语言特性如闭包,迭代器等,既运行迅速占用内存也很少. 出于性能考量,有时会导致学习成本和开发效率的降低.比如其他语言常见的语法,rust未必能提供.另一方面,性能也可能导致透明性和广泛性的损失,因为很多性能优化依赖于细节的屏蔽.

目前来看,rust提供了和C/C++相当的运行效率. 类似于C++, rust也尽量使用零成本抽象,在汇编层面并未增加过多运行负担.rust性能优化的一个例子是Iterator,迭代器比开发者手写的循环效率更高,因为迭代器不需要做越界检查等等.

零成本抽象默认最优设计*是性能优化的两个手段.

零成本抽象

不用的东西就不用付钱.更进一步:你所使用的代码,你不能再手工编写得更好了.

默认最优设计

rust的很多细节是故意允许未指定的.比如结构体只要未声明为repr,则rust编译器就可以自行优化重排其中的字段,从而更加紧凑.当然这些优化会导致透明性和广泛性的损失,这也是为什么rust又提供了repr关键字.


Supportive(学习成本)

the language, tools, and community are here to help

语言本身,相关工具和社区都尽可能地对开发者更加友好, 希望开发者学习成本尽可能低.但是作为受限于更高设计目标的可靠性和性能,因此总的来讲rust的学习曲线还是比较陡峭的.

这一点从rust相关的文档社区,甚至编译器的细节都能感受到. rust在编译时,相较于其他语言确实会稍微困难些,但是其编译提示真的是非常nice.不仅指出了问题所在,还会给出修复建议.


Productive(开发效率)

a little effort does a lot of work

rust希望通过提供大量强大的可复用组件来赋予开发者快速构建复杂系统的能力,从而具有很高的开发效率.

rust语言本身提供的crate机制非常好用,类似于python的pip. 早期设计的语言如C/C++在设计之初没有考虑到这一点,导致需要通过后期的工具去弥补.从开箱即用的角度来看,确实明显不如这些00后的语言.

保证开发效率的手段:

  1. 繁荣的生态系统
  2. 稳定的版本及更新方式
  3. rustfmt工具
  4. 可移植性

Transparent(底层操作)

you can predict and control low-level details

从rust到汇编层面这样的底层机器代码转换是很直接的.同时语言层面提供了直接控制底层细节的能力,这就为rust作为系统级语言提供了能力.

C语言从语言到汇编就很直接,但是C++在编译器中干了太多的魔法,导致就不是很直接.坦白讲,你就不得不学习很多语言层面的约定,加重了额外的心智负担.

底层操作能力某种程度上会导致开发效率降低和学习成本上升, 毕竟这需要暴露更多地底层细节.

避免全局/隐性成本

rust努力避免带来默认全局损耗的特性,这也是Stroustroup所说的零成本抽象的关键部分.你不需要为你没有的东西付费.这也是为什么rust使用了所有权机制而不是垃圾回收机制.

很明显,垃圾回收机制对于开发者是非透明且不可预测的.带有垃圾回收机制的语言明显不适合底层开发场景.


Versatile(通用性)

you can do anything with rust

rust拥有广泛的适应性.从最简单的脚本到web服务器,WebAssembly再到内核扩展模块和Os,应该说虽然rust目前还没有很有统治力的杀手级应用,但是它的应用范围是非常广阔的.

目前python,java等虽然很火热,但是由于其天然的设计缺陷,一些特定领域它们是注定无法进入的.

rust将系统所有核心能力都暴露给开发者.在任何时候,开发者都能直接使用rust语言完成所有工作,当然这会带来额外的一些学习和使用成本. 比较典型的例子是unsaferepr(c)

如何成为更好的rust社区成员

Be kind and considerate

在社区中,请一定要保持友善和体贴.

Bring joy to the user

rust语言的首要目标是希望开发者更加高效,更加喜欢使用. 如果可以的话,能喜欢rust社区就更好了.

Show up

展示自己的专业知识,并为你认为正确的事情坚持.

Recognize other’s knowledge

每个人都有自己的盲区,rust社区一直在寻求外部的意见,同时在不断改进.

Start somewhere

理想的设计需要不断地迭代. 目标远大,但从小处着手. 当你学到更多的时候,不要害怕改变和重构.

Follow through

知行合一, 坦白承认自己做不到事情,It’s OK. 没有人是全才.

Pay it forward

将能力传递出去. 有意识地培养新的成员,并认真辅导他们.

Trust and delegate

信任和托付 赋予他人权力,意味着让他们以自己认为最好的方式做决定.

小结

我个人感觉通过本文去了解rust的设计理念和社区文化, 从而去了解rust背后的理念. 在学习rust语言时,很多时候我们都是学了语法特性是什么(What),了解了如何使用(How).通过本文的学习,我们可以更多地掌握这些特性设计的背后(Why).

本文主要是摘录重点, 随便写了些自己的看法. 更详细的内容请移步参考资料3

参考资料

  1. Rustacean Principles
  2. Rustacean Principles website
  3. Rustacean Principles github repo