译者序
作为系统级语言事实上的标杆,C/C++语言诞生至今已经四十余年了。四十年历史的积累从某种角度上讲亦是四十年的负担。为了开发出运行正确的软件,我们需要投入数年的时间来学会如何避免臭名昭著的漏洞,但即便是最为谨慎的开发者,也无法保证自己的程序万无一失。这些漏洞不仅会导致计算机崩溃,还会带来许多意想不到的安全性问题。特别是随着互联网技术的飞速发展,所有人的私密信息都有可能因为这类安全性问题而赤裸裸地暴露在陌生人的面前。
有些语言,比如C#等,试图使用庞大的运行时系统来解决这一问题,其中最常见的解决方案便是垃圾回收(Garbage Collection)机制。这种机制在保证了内存安全的同时,却在某种程度上剥夺了程序员对底层的控制能力,并往往伴随着性能上的额外损耗。
正是在这样的背景之下,Rust应运而生。
Rust站在了前人的肩膀上,借助于最近几十年的语言研究成果,创造出了所有权与生命周期等崭新的概念。相对于C/C++等传统语言,它具有天生的安全性;换句话说,你无法在安全的Rust代码中执行任何非法的内存操作。相对于C#等带有垃圾回收机制的语言来讲,它遵循了零开销抽象(Zero-Cost Abstraction)规则,并为开发者保留了最大的底层控制能力。
Rust从设计伊始便致力于提供高水准的人体工程学体验。你可以在Rust中看到代数数据类型、卫生宏、迭代器等饱经证明的优秀语言设计,这些刻意的设计能够帮助你自然而然地编写出高效且安全的代码。在语言本身之外,Rust核心开发团队还规划并实现了一系列顶尖的工具链——从集成的包管理器到带有依赖管理的构建工具,再到跨越编辑器的自动补全、类型推导及自动格式化等服务工具。
Rust由开源基金会Mozilla推动开发,它的背后有一个完善且热情的社区。年轻的Rust正在众人合力之下不断进步,许许多多像你我一样的开发者共同决定着Rust的前进方向。你能够在Rust的托管网站GitHub上追踪到最新的源代码及开发进展,甚至是参与到Rust本身的开发之中。
但不得不承认的是,Rust独特的创新性也给我们带来了突兀的学习曲线。这些概念与传统语言雕刻在我们脑海中的回路是如此的不同,以至于使众多的初学者望而却步。这让人无比遗憾。为了解决这个问题,Rust核心团队的Steve Klabnik和Carol Nichols共同撰写了本书。他们由浅入深地介绍了Rust语言的方方面面——从基本的通用概念开始,到模式匹配、函数式特性、并发机制等实用工具,再到所有权、生命周期等特有概念。除此之外,本书还穿插了众多的代码片段及3个完整的项目开发实践案例。我们相信本书能够帮助所有期望评估、入门、提高及研究Rust语言的软件开发人员。
最后,我们非常高兴能够参与此次的翻译工作。在长久以来的学习过程中,社区内热情的Rust爱好者们提供了许多无法言尽的帮助,而这次的工作则给予了我们回馈社区的机会。感谢电子工业出版社牵头引进了这样一本官方图书,感谢编辑刘恩惠在翻译过程中的包容和理解,并在后期进行了大量的编辑工作。没有他们,就没有本书最终的完成。
碍于能力有限,对于本书中可能出现的错误,还望读者海涵;我们会随着Rust的迭代升级,不断地对本书进行更新与勘误。
序
虽然不是那么明显,但Rust编程语言的核心在于赋能:无论你正在编写什么样的代码,Rust赋予的能力都可以帮助你走得更远,并使你可以在更为广阔的领域中充满自信地编写程序。
例如,完成某些“系统层面”的工作需要处理内存管理、数据布局及并发的底层细节。我们习惯于将这些领域内的编程视作某种神秘的魔法,只有少部分被选中的专家才能真正深入其中。他们需要投入数年的时间来学习如何避免该领域内那些臭名昭著的陷阱,但即便是最为谨慎的实践者,也无法避免自己的代码出现漏洞、崩溃或损坏。
通过消灭这些陈旧的缺陷并提供一系列友好、精良的开发工具,Rust极大地降低了相关领域的门槛。需要“深入”底层控制的程序员可以使用Rust来完成任务,而无须承受那些常见的崩溃或安全性风险,也无须持续学习那些不断更新的工具链。更妙的是,这门语言旨在引导你自然而然地编写出可靠的代码,这些代码可以高效地运行并运用内存。
拥有底层代码编写经验的开发者可以使用Rust来实现“更具野心”的项目。例如,在Rust中引入并行是一种相对低风险的操作:编译器会为你捕捉那些常见的经典错误。你可以在代码中采用更为激进的优化策略,而无须担心意外地引发崩溃或引入漏洞。
但Rust的用途并不单单局限于底层系统编程,它极强的表达能力及工作效率足以帮助你轻松地编写出CLI应用、Web服务器及许多其他类型的代码——你会在本书中看到前两个领域内的简单示例。使用Rust还意味着你能够在不同的领域中构建相同的技能体系;你可以编写Web应用来学习Rust,并将这些技能应用到树莓派(Raspberry Pi)上。
本书全面地介绍了Rust赋予用户的诸多可能性,它采用了通俗易懂的语言以期帮助你理解有关Rust的知识。除此之外,本书还能从整体上提升你对编程的理解和信心。让我们一起来打开新世界的大门吧!欢迎加入Rust社区!
Nicholas Matsakis和Aaron Turon
前 言
欢迎阅读《Rust权威指南》,我们会在本书中深入浅出地向你介绍Rust语言!
Rust是一门可以帮助你开发出高效率、高可靠性软件的编程语言。以往的编程语言往往无法同时兼顾高水准的工程体验与底层的控制能力,而Rust则被设计出来挑战这一目标,它力图同时提供强大的工程能力及良好的开发体验,在给予开发者控制底层细节能力(比如内存操作)的同时,避免传统语言带来的诸多麻烦。
谁是Rust的目标用户
基于各种各样的原因,Rust对于许多人来讲都是一门相当理想的语言。现在让我们看一看其中最重要的一些群体。
开发团队
Rust已经被证明可以高效地应用于大规模的、拥有不同系统编程背景的开发团队。底层代码总是容易出现各种各样隐晦的错误,对于大部分编程语言来说,想要发现这些错误,要么通过海量的测试样例,要么通过优秀程序员细致的代码评审。而在Rust的世界里,大部分的错误(甚至包括并发环境中产生的错误)都可以在编译阶段被编译器发现并拦截。得益于编译器这种类似于守门员的角色,开发团队可以在更多的时间内专注于业务逻辑而非错误调试。
当然,Rust也附带了一系列面向系统级编程的现代化开发工具:
Cargo 提供了一套内置的依赖管理与构建工具。通过Cargo,你可以在Rust生态系统中一致地、轻松地增加、编译及管理依赖。
Rustfmt 用于约定一套统一的编码风格。
The Rust Language Server 则为集成开发环境(IDE)提供了可供集成的代码补全和错误提示工具。
通过使用上述工具,开发者可以有效率地进行系统级编程。
学生
对于那些有兴趣接触系统编程的学生而言,Rust也是一个非常好的选择,已经有不少人基于Rust来学习诸如操作系统开发之类的课程。另外,我们拥有一个非常热情的社区,社区成员们总是乐于回答来自初学者的各种问题。Rust开发团队希望通过本书让更多的人,特别是学生,能更加轻松地接触、学习系统编程的各种概念。
企业
目前已经有数百家或大或小的企业,将Rust用于生产环境并用它来处理各式各样的任务。这些任务包括命令行工具开发、Web服务开发、DevOps工具开发、嵌入式设备开发、音频图像分析转码、数字货币交易、生物信息提取、搜索引擎开发、物联网开发、机器学习算法研究,以及Firefox网络浏览器中的大部分功能开发。
开源开发者
当然,我们欢迎所有愿意参与构建Rust编程语言本身,或者周边社区、开发工具及第三方库的开发者。你们的贡献对于构建一个良好的Rust语言生态环境非常重要!
重视速度与稳定性的开发者
Rust适用于那些重视速度与稳定性的开发者。当谈论到速度时,我们不仅是指Rust程序可以拥有良好的运行时效率,而且还期望Rust可以提供良好的开发时效率。得益于Rust编译器的静态检查能力,我们可以稳定地在开发过程中增添功能或重构代码。与此形成鲜明对比的是,在缺少这些检查能力的语言中,开发者往往恐惧于修改那些脆弱的遗留代码。此外,得益于对零开销抽象这一概念的追求,开发者可以在无损耗的前提下使用高级语言特性。Rust力图使安全的代码也同样高效。
当然,这里提到的只是Rust使用场景中最有代表性的一部分用户,Rust语言也希望能够服务于尽可能多的其他开发者群体。总的来说,Rust最大的目标在于通过同时保证安全与效率、运行速度与编程体验,消除数十年来程序员们不得不接受的那些取舍。不妨给Rust一个机会,让我们一起来看一看它是否适合你。
谁是本书的目标读者
对于本书的读者,我们假设你已经使用过某种其他编程语言。虽然我们努力使本书的内容能够被具有不同编程背景的读者所接受,但我们不会花太多时间去讨论一些基本的编程概念。如果你对于编程是完全陌生的,那么你最好先阅读一些入门类的编程图书。
如何阅读本书
通常而言,我们假定读者按顺序从头到尾阅读本书。一开始我们会简单地介绍一些概念,接着在随后的章节中逐步深入,并有针对性地对其中的细节进行讨论。后面章节的讨论建立在前面章节引入的概念之上。
在本书中,你会发现两种类型的章节:概念讨论类章节和项目实践类章节。在概念讨论类章节中,你会接触到Rust的某些特性;在项目实践类章节中,我们会利用之前已经讲解过的Rust特性来共同构建一些小程序。第2章、第12章、第20章属于项目实践类章节,其余章节属于概念讨论类章节。
第1章会介绍如何安装Rust,如何编写“Hello, World!”程序,以及如何使用Cargo来对它进行管理及构建。
第2章会从实践的角度对Rust语言进行介绍,这里我们会从较高的层次去覆盖一系列概念,并在之后的章节中逐步深入研究细节。如果你是一个实践派,想要立即动手编写代码,那么第2章正好适合你。第3章会介绍Rust中类似于其他语言的那些特性,心急的人也许会尝试跳过这一章,并直接阅读第4章中关于Rust所有权系统的内容。相反,如果你是一个特别重视细节的学习者,期望一步一步了解清楚每一个角落,那么我建议你跳过第2章,从第3章开始按顺序阅读,并在想要通过实践来巩固知识点时再返回第2章进行阅读。
第5章会讨论结构体和方法,第6章会包含枚举、match表达式及if let控制流结构的相关内容。你将学会在Rust中使用结构体及枚举来创建自定义类型。
在第7章中,你会了解到Rust中的模块系统及私有性规则,并学会如何使用它们来组织代码和设计公共接口(API)。第8章会介绍一些标准库中提供的常用数据结构,比如Vec(动态数组)、String(字符串)及HashMap(哈希表)。第9章会讨论Rust中关于错误处理的一些设计理念和工具。
第10章会深入讲解关于泛型、trait(特征)和生命周期的概念,它们赋予了你复用代码的能力。第11章则是关于如何在Rust中构建测试系统的内容。即便是有Rust的安全检查,我们也需要通过测试来保障业务逻辑上的正确性。在第12章中,我们会实现命令行工具grep的一些功能子集,用于在文件中搜索某些特定文本,为此我们会用到很多前面章节中讨论的概念。
第13章会讨论Rust中与函数式编程相关的概念:闭包与迭代器。在第14章中,我们会更加深入地了解Cargo,以及与他人共享代码库的一些最佳实践。第15章会讨论标准库中的智能指针,以及它们所实现的相关trait。
在第16章中,我们会讨论多个不同的并发编程模型,并看一看Rust是如何让多线程编程变得不那么恐怖的。第17章则着眼于比较Rust与常见的面向对象编程范式的不同风格。
第18章是关于模式及模式匹配的介绍,它们给Rust语言带来了异常强大的表达能力。第19章则会覆盖一些有趣的高级主题,包括对不安全Rust、宏、trait、类型、函数及闭包的更深入的讨论。
终于,在第20章中,我们将从底层开始实现一个完整的多线程Web服务器!
最后的附录内会包含一系列有关语言的实用参考资料。附录A会列举Rust中全部的关键字,附录B会列举Rust中所有的运算符及其他符号,附录C会包含标准库中提供的可派生trait,附录D会介绍一些有用的开发工具,附录E会解释Rust中的版本机制。
当然,不管你怎样阅读本书都是可以的。假如你想要跳过某个特定的章节,那就跳过吧,你可以在感到疑惑的时候再返回略过的那些部分。用你觉得最舒服的方式去阅读本书就好!
在学习Rust的过程中,掌握如何阅读编译器显示的错误提示信息是一项尤为重要的能力:它们能够引导你编写出可用的代码。为此,我们会故意提供许多无法通过编译的示例,进而展示相关情境下编译器输出的错误提示信息。所以,在本书中随意挑选出来的示例代码也许根本就无法通过编译!请仔细阅读上下文来确定你尝试运行的示例代码是否是一段故意写错的代码。在大部分情况下,我们会指引你将不能编译的代码纠正为正确版本。
致 谢
我们想要感谢那些参与了Rust开发的人们,这样一门令人惊叹的语言绝对值得去编写一本书。我们感谢Rust社区中的所有人,你们的热情构建了一个值得更多伙伴参与进来的伟大社区。
我们要特别感谢那些阅读过本书早期版本并提供了众多反馈、错误报告及修改请求的读者。还要特别感谢Eduard-Mihai Burtescu与Alex Crichton提供的技术审查,以及Karen Rustad Tölva设计的封面。感谢我们在No Starch的编辑团队,Bill Pollock、Liz Chadwick与Janelle Ludowise协助完善并完成了本书的出版工作。
Steve想要感谢一位异常出色的合著者Carol,她使本书能够更快、更好地完成。另外,还要感谢Ashley Williams,她对本书的整个编写过程提供了难以想象的支持。
Carol想要感谢Steve激起了自己对Rust的兴趣,并给予了自己共同编写本书的机会。感谢家人长久的爱与支持,特别是丈夫Jake Goulding及女儿Vivian。