Rust-0.概述

感觉近几年Go语言很火,不过个人并不喜欢。我个人的意见是,其内部实现非常值得围观学习,但是其作为编程语言的设计实在是惨不忍睹,特别是在21世纪有那么多经验教训可以借鉴的情况下,由Google这么一个名气甚大的公司开发的语言,令人大失所望。

按我的判断,近些年的新语言中,最靠谱,最有希望在工业环境大展身手的,就是Rust。故而尝试安利一下。当然我觉得目前的Rust还需要再开发几年才能真正投入实际生产,但是这么有想法的项目在国内关注的人寥寥,不由得有些不平。不过即使在欧美,Rust也属于相对小众,但接触过的人评价都较好的情况,比如可见StackOverflow开发调查2016年的结果2017年的结果,Rust连续两年在最受喜爱的编程语言中以较大的优势排在第一(因为这个是按百分比比较的),但是从绝对人数来看,Rust并不突出。

之后我会按照我认为的语言特性的重要程度的顺序来介绍,并且我会自行脑补这样的设计体现了什么样的思想。因为是安利向的,主要是介绍Rust重要的优点和特点,只要面向已经有编程基础的,说明Rust好在哪里。所以并不准备把语言基本的细节系统地过一遍,有兴趣的可以自行了解。

而本篇主要是对Rust语言的总体介绍。

另外,知乎上有个Rust编程专栏,我觉得写得不错。我看完之后写出来的文章可能会不自觉地带有里面的有些观点,或自觉地借用一些知识点和例子)。

名字由来

关于Rust的名字由来,根据道听途说,整理起来大概是这样的。Rust在英语的中意思是腐蚀生锈,很有裸露金属(bare metal)和古老的感觉,而Rust可以编写运行于裸机(bare metal)的程序,同时比较注重吸收其他语言中久经考验的特性,设计上比较复古。另外Rust是Robust(稳健)和Trust(信任)的子串,和Rust注重安全的特性比较契合。

设计目标

按官方自己的说法,Rust的设计目标是:

  • Safety(安全)
  • Speed(速度)
  • Concurrency(并发)
    Rust的定位是一门通用的系统编程语言,上面三个设计目标都很好理解。除此之外我们在Rust的设计中还能看到这样的倾向,即主要提供通用的基础设施,故语言核心、核心库和标准库尽量小;并具有足够扩展性,靠近应用层的功能交给库,带着这样的认知,我们看Rust的设计可能更能理解一点。

按我的看法呢,速度主要是零开销抽象(zero-cost abstraction),这个大概是来源于C++的思想,主要是虽然提供高层抽象,但尽量不影响最终程序运行的性能,这个思想的影响体现在语言的方方面面,要说起来到处都是,有一些可能不得不对语言本身或库的接口有影响,当然最好还是对使用者透明的优化。

而在并发上,Rust把提供并发模型的任务交给了库(可以实现各种不同的并发模型,这得益于Rust良好的扩展性),而Rust拥有独特的机制,保证线程安全,而且这种机制不像某些语言只能用于自带的类型,而是可以提供给所有的用户定义类型,所以自然有很多可安全并发的库。

所以依我来看,Rust最核心的设计思想是安全,所以接下来对Rust的介绍也会以安全为核心来介绍。安全,狭义的讲比如内存安全和线程安全;广义上,我觉得可以理解为帮助提高程序的质量。Rust不仅仅做到内存和线程安全,其实也有很多设计可以帮助较少其他的逻辑错误。

不追新的设计

正如它的名字由来,Rust语言基本没有创造什么崭新酷炫的特性,而是吸收很多已有的经验(当然只用过一些主流语言的人大概会觉得里面有不少新奇的东西)。而且吸收的这些特性都不是Rust的主要卖点,只是借助他们实现自己的目标。

对于一些古老的编程语言,里面多多少少的设计失误,Rust也进行了不少合理的微调。

要说Rust有什么创新之处的话,我觉得是围绕安全的设计目标,借助一些语言特性,形成对安全问题的整套解决方案。

安全的意义

安全的好处大家当然都清楚,也不用我赘述,就随便讲个几点:

  • 提高代码的正确率,和项目的质量
  • 减少程序的调试和测试时间,实际上减少了总体的开发时间

安全的代价

听说Rust这么厉害,安全又效率,总不能完美无缺,那么代价是什么呢?

比如Java也是安全的,付出的代价是运行效率,在运行时增加了完善的安全检查,将不安全的问题转化成了易追踪,易处理的异常。但是静态检查比运行时检查要困难很多,我们可以看到市面上有很多C或者C++的静态分析工具,但都不能完美解决代码的安全问题。

这里我们要看看Rust是怎么实现其安全的,如何能够做到C和C++做不到的事情:

  • 首先和C++一样,足够高层的抽象能减少不少需要手动实现的琐碎细节,也帮助减少错误。
  • 真正重要的是,其实这里非常有意思,即把语义错误(即逻辑错误)转化为语法错误。Rust不像C和C++这么自由,其严格的语法和库接口直接限制了很多可能导致问题的代码无法被编译,而不需要像静态检查工具这样在非常自由的场景下尝试找出逻辑错误。

一般编程语言是逻辑没问题的代码一定能编译,但能编译的不一定没问题。Rust则是逻辑没问题的代码不一定能编译通过,但能编译通过的一定不会有安全问题。这其实也是一种思想,即无法解决的问题,其实可以换一条思路,并不解决这个问题本身,而是我们是否真的需要解决这个问题,这个问题本身可能可以简化。

不过这样确实带来了一定的问题,就是代码本身的限制增加了,刚开始使用的时候会非常不习惯,可能需要被迫使用一种不同的风格,易用性有些下降,对使用门槛有一定的提高。但是,同时

  • 熟练的Rust程序员会更少地遇到与编译检查的冲突(本条凑数)
  • Rust一个重要特性non-lexical lifetimes已经开搞了,这个特性简单来讲就是引入更加智能的生命周期分析,在仍旧保证安全性的前提下,放宽了编译检查的限制,让更多的安全代码成在语法上成为合法的
  • Rust仍然一直努力从各方面提高其易用性

安全以外

我觉得Rust的相比其他语言的优势在于:

  • 相比C,它提供了很多方便的高层抽象
  • 相比其他很多同样提供了类似抽象的高级语言,提供了更高的运行速度,并具有直接和底层硬件交互的能力,已经有人用Rust实现了一个操作系统Redox
  • 相比C++这样既有高层抽象又有运行效率的语言,其设计更加统一简洁,语法更加严格,减少很多误用和滥用

另外我看来Rust的设计具有良好的扩展性:

  • 基于trait的面向对象模型(为了解决面向对象的多继承问题,面向对象也有不同的模型,相比与C++机制复杂的多继承和Java功能较弱的interface,trait是一个相当不错的解决方案),利用一些特殊trait可做到运算符重载,自动资源释放,安全并发等
  • 利用宏进行编译阶段的代码变换。首先,不同于C的宏,Rust的宏作用在词法分析之后,已经形成token序列,相比C宏的字符串替换,更加严谨和安全;另外除了一般的声明式宏(declartive macro),Rust还有过程式宏(procedural macro),不同于利用特殊语法直观声明变换规则的声明式宏,过程式宏可以看作一个函数,以变换前的代码作为输出,输出变换后的代码,因为在可以直接使用语言的几乎所有功能,我们能够进行比声明式宏自由得多的变换,是一种限制较小的元编程手段。