跳转到内容

Rust 简介

Rust 是一门系统编程语言,用途和 C、C++ 差不多:操作系统、游戏引擎、浏览器、数据库,还有那些看重速度和控制力的命令行工具。

它的特别之处在于:你能得到底层语言的性能,却不用再踩那些经典的坑。在 C 里,一不小心就会读到已经释放的内存,或者引发数据竞争。而在 Rust 里,这样的代码通常连编译都过不了,编译器会在构建阶段就拦住你。

Rust 最早是 Graydon Hoare 的个人项目,后来他把它带到 Mozilla,获得了赞助。2015 年,Rust 发布了稳定的 1.0 版本。现在它由 Rust 基金会(Rust Foundation)(英文)和一个庞大的开源社区共同维护。

过去,你只能在两种取舍之间二选一:

  • 底层语言(C、C++):速度快、贴近硬件,但内存要你自己手动管理。一旦出错,就会导致崩溃和安全漏洞。
  • 高级语言(Python、Java、Go):安全又好写,但依赖垃圾回收器(garbage collector),会牺牲一些性能和可预测性。

Rust 的核心想法是第三条路:它用一套叫作所有权(ownership)的机制(本教程后面会讲),在编译时保证内存安全。没有垃圾回收器,也不用手动调用 free(),什么时候不再需要某块内存,由编译器来判断。

下面大致列出了 Rust 和你可能熟悉的语言之间的位置关系:

语言 速度 内存安全 垃圾回收器
C / C++ 快 手动管理,容易出错 无
Go 不错 安全 有
Python 较慢 安全 有
Rust 快 安全(编译时检查) 无

结论是:Rust 想同时做到 C 级别的速度和高级语言的安全。想看更详细的、配有真实代码的逐项对比,请看 Rust 与 C++、Go、Python 对比。

你很可能早就在用 Rust 写的软件了,只是自己不知道:

  • Firefox:渲染引擎的一部分是用 Rust 写的
  • Cloudflare 和 Discord:对性能要求很高的后端服务
  • Linux 内核:现在已经接收用 Rust 编写的驱动程序
  • 命令行工具:像 ripgrep(英文)、bat、fd 这些又快又受欢迎的工具
  • WebAssembly:想在浏览器里运行接近原生速度的代码,Rust 是首选之一

现在还不用弄懂每个细节,只要感受一下它有多好读:

fn main() {
let name = "Rustacean";
println!("你好,{name}!");
}

输出:

你好,Rustacean!
▶ 动手试一试

“内存安全”听起来很抽象,我们来看一个具体的例子。假设你有一个包含 3 个分数的列表,却想取第 10 个,而它根本不存在。

在 C 里,这是允许的。程序会悄悄读取列表后面内存里碰巧存着的东西。你可能拿到一个随机数,可能程序崩溃,也可能留下安全漏洞,而且没有任何提示。

Rust 不会放过这种错误。只要编译器能看出问题,就会拒绝构建程序:

fn main() {
let scores = [90, 85, 77];
println!("{}", scores[9]);
}
error: this operation will panic at runtime
--> src/main.rs:3:20
|
3 | println!("{}", scores[9]);
| ^^^^^^^^^ index out of bounds: the length is 3 but the index is 9

这条错误信息的意思是:“这个操作在运行时会 panic:索引越界,长度是 3,索引却是 9。”

如果你不确定某个元素是否存在,Rust 也提供了一种礼貌的问法。.get() 会回答“在这儿”或者“这里什么都没有”(None),而不是塞给你一堆垃圾数据:

fn main() {
let scores = [90, 85, 77];
println!("第一个分数:{}", scores[0]);
println!("第十个分数:{:?}", scores.get(9));
}

输出:

第一个分数:90
第十个分数:None
▶ 动手试一试

[...]、.get() 和 None 现在还不用管,后面的 Rust 数组和 Option 会好好讲。眼下只要记住一点:“读了不该读的内存”这一整类 bug,要么在程序运行前就被发现,要么在运行时被安全地处理掉。

说实话,头一两周可能会让人有点抓狂。所有权和借用(borrowing)这些概念确实是全新的,你觉得没问题的代码,编译器也可能直接拒绝。刚开始觉得别扭很正常,这种磕磕绊绊其实是编译器在教你写更安全的代码,而且大多数人开窍得比自己预想的快。

这份教程就是为了把这条学习曲线变得平缓:小步前进,真实的例子,每段代码都有 动手试一试 按钮。

修改“先尝一口”里的程序,让它用名字和你打招呼,再加一行输出 欢迎来到 Rust!。提示:每个 println! 打印一行,所以你需要两个。

查看答案
fn main() {
let name = "小明";
println!("你好,{name}!");
println!("欢迎来到 Rust!");
}

输出:

你好,小明!
欢迎来到 Rust!
▶ 动手试一试

把单词 Rust 和年份 2015 分别存到两个名字里,然后用它们打印出这句话:Rust 1.0 于 2015 年发布。提示:同一个 println! 里可以放不止一个 {name}。

查看答案
fn main() {
let language = "Rust";
let year = 2015;
println!("{language} 1.0 于 {year} 年发布。");
}

输出:

Rust 1.0 于 2015 年发布。
▶ 动手试一试
  • Rust 是一门又快又安全的系统编程语言:拥有 C 级别的速度,却没有垃圾回收器。
  • 它通过所有权在编译时防止内存 bug。
  • 浏览器、操作系统内核、云服务、命令行工具和 WebAssembly 都在用它。
  • 学习曲线确实存在,但不长,而且编译器站在你这边。

下一步:在自己的电脑上安装 Rust,运行你的第一个程序。

小测验

1. Rust 不用垃圾回收器,是怎样做到内存安全的?

2. 根据对比表,Rust 和 Go 有什么共同点?

3. Rust 开发者怎么称呼自己?

得分: 0 / 3