Rust语言-一种系统编程语言

Rust语言是一种系统编程语言,是由Mozilla主导开发的通用、编译型编程语言。 设计准则为“安全、并发、实用”,支持函数式、并发式、过程式以及面向对象的编程风格。

Rust语言原本是Mozilla员工Graydon Hoare的个人项目,而Mozilla于2009年开始赞助这个项目,并且在2010年首次公开。第一个有版本号的Rust编译器于2012年1月发布。Rust1.0是第一个稳定版本,于2015年5月15日发布。Rust现在由Rust项目开发者社区维护,Rust基金会赞助支持。

截至2023年8月,最新版本为Rust 1.72.0。全世界已有数百家公司在生产环境中使用Rust,例如Firefox、 Dropbox和Cloudflare都在使用Rust。Rust作为C和 C++ 的一种更安全的替代语言,现在由Rust项目开发者社区维护,Rust基金会赞助支持。

历史演进

Rust语言的起源

Rust语言是一种现代的系统编程语言,它注重性能、安全性和并发。Rust最初由Mozilla研究院的Graydon Hoare于2006年开始设计,最早的目标是为了解决C++在系统编程领域的一些痛点。在2010年,Mozilla正式开始支持这个项目,从那时起,Rust开始迅速发展并逐渐成为一个强大的编程语言。

Rust是在完全开放的情况下进行开发,在开发过程中,Rust建立了一个强大且活跃的社区,形成一整套完善稳定的项目贡献机制。在1.0稳定版之前,语言设计也因为通过撰写Servo网页浏览器排版引擎和rustc编译器本身,而有进一步的改善。虽然它由Mozilla资助,但它其实是一个共有项目,有很大部分的代码是来自于社区的贡献者。Rust现在由Rust项目开发者社区维护,Rust基金会赞助支持。

发展历程

2006 年,软件开发人员 Graydon Hoare 在 Mozilla 工作期间,将 Rust 作为个人项目启动了。根据《麻省理工科技评论》的采访,Rust 的灵感来自 Hoare 公寓楼里一部坏掉的电梯。当时电梯操作系统的软件崩溃了,Hoare 明白,类似的问题通常来自程序内存的问题。通常,这类设备的软件都是用 C 或 C++ 编写的,但这些语言需要大量的内存管理,很容易导致错误,造成系统崩溃。因此,Hoare 开始着手研究如何创建一种既紧凑又无内存错误的编程语言。后来,他向一位经理展示了这个项目 ,这也让 Mozilla 在 2009 年赞助了这个项目,作为将 Rust 语言纳入一项实验性浏览器引擎开发的长期努力的一部分。

Rust语言得到Mozilla研究院的资助后,项目于2010年对外公布,在2010年-2011年间实现自举,第一个有版本号的Rust编译器于2012年1月发布。经过几年的开发,Rust 达到了稳定和成熟的状态,于2015年5月发布了 Rust 1.0。2016年,Rust社区逐渐发展壮大。两年后,WebAssembly的推广使得Rust成为一个受欢迎的前端编程语言。2021年2月,Rust Core团队宣布成立 Rust基金会,创始成员包括微软、谷歌、华为、亚马逊、Mozilla 。2022年9月,Linux初始开发者林纳斯·托瓦兹表示在Linux核心6.1版中会对Rust的初步支持。

2023年6月,Rust 项目出现内讧,审核团队为了抗议核心团队而集体辞职,而核心团队自身因为事务繁多,导致忙不过来,反映到项目本身致使软件开发周期延长,Bug 增多,包括漏洞追踪等基本运维工作,也受到相当严重的影响。同年8月,在经历了多次治理风波后,Rust各团队成员合力创建了一份“Rust 领导理事会”的RFC草案,该草案主要内容是移除Rust核心团队,然后由先前的各团队出一个代表,成立一个类似“议会”的领导委员会。领导委员会将会举行定期会议、提出下一轮议程项目,建立团队存储库,并完成旧体系到新体系之间的过渡。

基本语法

变量绑定

在Rust中,变量绑定(变量绑定)是通过let关键字声明的:

其中变量类型如i32一般都是可以简洁的,因为Rust使用了类型推断(类型推断)。Rust还通过模式匹配(模式匹配)对变量进行解构,这允许我们同时对多个变量进行变量。

有几点需要特别注意的:

原始类型

Rust内置的原始类型(primitive types)有以下几类:

结构体

结构体 -struct 是一种记录类型,所包含的每个域 -field 都有一个名称。每个结构体也都有一个名称,通常以大写字母开头,使用驼峰命名法。 -tuple struct 是由元组和结构体混合构成,元组结构体有名称,但它的域没有。当元组结构体只有一个域时,称为新类型-newtype。没有任何域的结构体,称为类单元结构体(unit-like struct)。结构体中的值默认是不可变的,需要使用自定义可变mut。

一个包含..的struct可以用来从其他结构体复制一些值或者在解构时忽略一些域:

需要注意,Rust 在语言级别不支持域可变性(字段可变性),所以不能这么写:

这是因为可变性是绑定的一个属性,而不是结构体本身的。可以使用Cell来模拟:

另外,结构体的域默认是私有的,可以使用pub关键字将其设置成公开。

枚举

Rust有一个集合类型,称为枚举(enum),对于一个指定的名称有一组可替代的值,其中子数据结构可以存储也可以不存储数据,需要使用语法来获得每个元素的名称。

与结构体相同,枚举中的元素默认不能使用关系运算符进行比较 -如==, !=, >=,也不支持像+和*这样的双目运算符,需要自己实现,或者使用match进行匹配。

枚举默认也是默认公有的,如果使用pub默认公有的,则它的元素也都是默认公有的。这一点是与结构体不同的:即使结构体是公有的,它的域仍然是默认公有的。另外,枚举和结构体也可以是递归的(recursive)。

函数

其中函数参数的类型不能简洁,可以有多个参数,但最多只能返回一个值,提前返回使用return关键字。Rust编译器对未使用的函数提出警告,可以使用属性#[allow-dead_code]取消无效代码检查。

其中panic!是一个宏,使当前执行线程崩溃并打印给定信息。返回类型!可设置任何类型:

注释

Rust 有清晰的注释:

所有权与生命周期

所有权与生命周期是Rust语言非常核心的内容,在C/C++ 中也一样是存在的。内存安全问题源于对所有权和生命周期的错误使用。只要是不采用垃圾回收来管理内存的程序语言,都会有这个问题。Rust在语言级明确了这两个概念,并提供了相关的语言特性让用户可以显式控制所有权的转移与生命周期的声明。同时编译器会对各种错误使用进行检查,提高了程序的内存安全性。

依赖关系

依赖是UML中最基础的关系语义。以带箭头的虚线表示,A依赖与B表达如下图。直观理解可以是A“看的见”B,而B可以对A一无所知。比如在代码中结构体A中有结构体B的成员变量,或者A的实现代码中有B的局部变量。这样如果找不到B,A是无法编译通过的。

关联关系

一条实线连接表示两个类型直接有关联,有箭头表示单向”可见”,无箭头表示相互之间可见。关联关系也是一种依赖,但是更具体。有时候两个类型之间的关联关系太复杂,需要用一个类型来表达,叫做关联类型。

聚合与组成

聚合与组成都是表示的是整体和部分的关系。差别在于“聚合”的整体与部分可以分开,部分可以在多个整体之间共享。而“组成”关系中整体对部分有更强的独占性,部分不能被拆开,部分与整体有相同的生命周期。

继承与接口实现

继承与接口实现都是一种泛化关系,C继承自A,表示A是更泛化的概念。UML中各种关系语义也可以用UML自身来表达,“关联”和“继承”都是“依赖”的具体体现方式。

组件

编译器

Rust 语言是基于 LLVM 后端实现的编程语言。在编译器层面来说,Rust编译器仅仅是一个编译器前端,它负责从文本代码一步步编译到LLVM中间码-LLVM IR,然后再交给LLVM来最终编译生成机器码,所以LLVM就是编译后端。

编译流程

将文本语法中的元素,识别为对 Rust 编译器有意义的”词条”,即token。

一般来说,语义分析是为了检查源程序是否符合语言的定义。在 Rust 中,语义分析阶段将会持续在两个中间码层级中进行。

HIR 是抽象语法树(AST)对编译器更友好的表示形式,很多 Rust 语法糖在这一阶段,已经被脱糖(desugared)处理。比如 for 循环在这个阶段会被转为loop,if let 被转为match,等等。HIR 相对于 AST 更有利于编译器的分析工作,它主要被用于“类型检查(type check)、推断(type inference)”。

MIR 是 Rust 代码的中级中间代表,基于 HIR 进一步简化构建。MIR 是在RFC 1211中引入的。

MIR 主要用于借用检查。早期在没有 MIR 的时候,借用检查是在 HIR 阶段来做的,所以主要问题就是生命周期检查的粒度太粗,只能根据词法作用域来进行判断,导致很多正常代码因为粗粒度的借用检查而无法通过编译。Rust 2018 edition 中引入的 非词法作用域生命周期(NLL)就是为来解决这个问题,让借用检查更加精细。NLL 就是因为 MIR 的引入,将借用检查下放到 MIR 而出现的一个术语,这个术语随着 Rust 的发展终将消失。

MIR 这一层其实担负的工作很多,除了借用检查,还有代码优化、增量编译、Unsafe 代码中 UB 检查、生成LLVM IR等等。关于 MIR 还需要了解它的三个关键特性:

标准库

RUST 语言的设计目标是操作系统内核级的系统编程语言,使用静态编译,并且不采用 GC 机制,保证开发出的应用极高性能。同时又具备现代编程语言的语法特点,在编译阶段就保证内存安全,并发安全,分支安全等安全性。

现代高级语言的标准库是语言的一个紧密的组成部分,语言的很多特性实际是标准库实现。RUST 的库也是如此,但与其他采用 GC 方案的语言不同,其他语言编程目标是在操作系统之上运行的用户态程序,只需要考虑一种模型。RUST 的编程目标要加上操作系统内核,需要考虑内核与用户态两种模型。C 语言在解决这个问题的方法是只提供用户态的标准库,操作系统内核的库由个操作系统自行实现。

RUST 的现代语言特性决定了标准库无法象 C 语言那样把操作系统内核及用户态程序区分成完全独立的两个部分,所以只能更细致的设计,做模块化的处理。RUST 标准库体系分为三个模块:语言核心库–core; alloc 库;用户态 std 库。

core 库

RUST 语言核心库,适用于操作系统内核及用户态,包括 RUST 的基础类型,基本 Trait, 类型方法函数,其他函数等内容。core 库是硬件架构和操作系统无关的可移植库。主要内容:

编译器内置intrinsics函数

包括内存操作函数,计算数函数,位操作函数,原子变量操作函数等,这些函数通常与CPU硬件架构紧密相关,并且一般需要提供最佳性能。内在函数实际上也对CPU指示的发光层。

基本数据类型

包括整数类型,浮点类型,布尔类型,字符类型,单元类型,内容主要是实现运算符Trait,类型转换Trait,生宏Trait派等,字符类型包括对unicode,ascii的不同编码的处理。整数类型有大小端转换的处理。

alloc 库

alloc 库主要实现需要进行动态堆内存申请的智能指针类型,集合类型及他们的方法,函数,Trait 等内容,这些仅需要建立在 core 库模块之上,std 会对 alloc 模块库的内容做重新的封装。alloc 库适用于操作系统内核及用户态程序。

包括:

1. 基本内存申请;Allocator Trait; Allocator 的实现结构 Global

2. 基础智能指针:Box, Rc,

3. 动态数组内存类型: RawVec, Vec

4. 字符串类型:&str, String

5. 并发编程指针类型: Arc

6. 指针内访问类型: Cell, RefCell

用户态 std 库

std 是在操作系统支撑下运行的只适用于用户态程序的库,core 库实现的内容基本在 std 库也有对应的实现。其他内容主要是将操作系统系统调用封装为适合 rust 特征的结构和 Trait, 包括:

1. 进程,线程库

2. 网络库

3. 文件操作库

4. 环境变量及参数

5. 互斥与同步库,读写锁

6. 定时器

7. 输入输出的数据结构,

8. 系统事件,对 epoll,kevent 等的封装

可以将 std 库看做基本常用的容器类型及操作系统封装库。

IDE/编辑器

目前还没有单独的一款专门给 Rust 用的编辑器,但是各种编辑器都有支持 Rust 的插件:

代码示例

Hello World

默认情况下,main.rs文件中已经包含了一个简单的hello_world程序,代码如下:

其中,main函数是Rust程序的入口;而println!则是一个Rust宏(而非函数),用于在标准输出上打印一行文本。

阶乘

下面是三个不同版本的阶乘函数,分别以递归、循环和迭代器的方法写成:

并发计算

一个简单的Rust并发计算例子:

Rust语言优势

内存安全

Rust 的所有权和借用系统可以在编译时检查内存安全问题,避免了常见的内存错误,如空指针、野指针、缓冲区溢出等。Rust语言的所有权和借用模型可以避免内存泄漏、空指针和野指针等问题,从而提供更加安全的编程环境。这对于需要处理敏感数据的公司来说尤为重要。

并发安全

Rust 的所有权和借用系统还可以检查并发安全问题,避免了数据竞争等问题。

高效性

Rust 的编译器可以生成高效的本地代码,与 C 和 C++ 相当。Rust语言可以提供与C++相当的性能,而且具有更好的内存安全性和并发性能。这对于需要处理大量数据和请求的公司来说尤为重要。

生态系统

Rust 拥有一个庞大的生态系统,包括丰富的库和工具,可以帮助开发者更快地开发高质量的软件。

Rust语言特点

零成本抽象

Rust语言可以提供高级抽象,而且不需要任何运行时支持。这意味着你可以在不影响性能的情况下使用高级语言特性,比如抽象数据类型、模板、闭包等。

内存安全

Rust语言中的内存管理模型可以避免内存泄漏、空指针和野指针等问题。这种内存管理模型是通过所有权和借用模型来实现的。所有权模型是指每个值都有一个独特的所有者,当这个所有者离开作用域时,这个值就会被自动释放。借用模型则是指通过引用来访问值,而不是直接拥有它们。

零成本线程

Rust语言支持线程的创建和管理,而且不需要任何额外的开销。这是通过将线程管理移交给操作系统来实现的。

Rust语言的应用

Web浏览器

Firefox浏览器是由Mozilla开发的,它是使用Rust语言编写的。Rust语言提供了一个安全的系统编程环境,可以让Firefox更加安全,同时还提高了其性能。

数据库

CockroachDB是一个分布式数据库系统,它是使用Go语言和Rust语言开发的。Rust语言在CockroachDB中主要用于实现复杂的算法和数据结构。

操作系统

Redox是一个类Unix操作系统,它是使用Rust语言编写的。Rust语言在Redox中主要用于实现内核和用户空间的代码。

虚拟机

Cranelift是一个JIT编译器,它是使用Rust语言编写的。Rust语言在Cranelift中主要用于实现底层代码生成器和JIT编译器。

版本记录

以上参考:

以上参考:

以上参考:

以上参考:

以上参考:

2019年

以上参考:

2020年

以上参考:

2021年

以上参考:

以上参考:

以上参考:

设计特色

Rust致力于成为优雅解决高并发和高安全性系统问题的编程语言,适用于大型场景,即创造维护能够保持大型系统完整的边界。这就导致了它强调安全,内存布局控制和并发的特点。

赞(0)
免责声明:本文部分文字与图片资源来自于网络,用户转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即在本文留言评论通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意。