Rust 入门:面向中文读者的全面介绍
引言
在当今软件开发领域,性能、安全性和并发性是永恒的追求。传统的系统编程语言如 C/C++ 提供了卓越的性能和对底层硬件的精细控制,但代价往往是复杂的内存管理、容易出错的并发模型以及由此带来的安全漏洞。而像 Java、Python、Go 等带有垃圾回收(GC)的语言虽然提高了开发效率和内存安全性,但在需要极致性能、低延迟或无运行时开销的场景下(如操作系统、嵌入式系统、高性能网络服务、命令行工具等),它们可能不是最佳选择。
正是在这样的背景下,Rust 应运而生。自 2015 年发布 1.0 版本以来,Rust 凭借其独特的优势——在不引入垃圾回收的情况下提供内存安全和无数据竞争的并发——迅速吸引了全球开发者的目光。它连续多年被 Stack Overflow 开发者调查评选为“最受欢迎的编程语言”,并在操作系统、Web 后端、命令行工具、WebAssembly、嵌入式等多个领域展现出强大的生命力。
对于中文世界的开发者而言,Rust 提供了新的可能性。无论你来自 C++、Java、Python、Go 还是其他语言的背景,Rust 都值得你去了解和尝试。本文旨在为中文读者提供一份全面的 Rust 入门指南,从核心理念到实际动手,带你一窥 Rust 的魅力。
什么是 Rust?
简单来说,Rust 是一种多范式、通用目的的编程语言。它专注于安全(Safety),特别是内存安全;性能(Performance),媲美 C/C++;以及并发性(Concurrency),消除数据竞争。
Rust 的设计哲学是“赋能每个人构建可靠且高效的软件”。它不是简单地“更好”的 C++ 或“没有 GC”的 Go,而是在语言层面引入了全新的所有权(Ownership)系统,配合借用(Borrowing)和生命周期(Lifetimes)的概念,在编译时强制检查内存安全,从而避免了空指针引用、数据竞争等常见错误,而无需运行时垃圾回收的开销。
Rust 既可以用于开发接近硬件的底层代码(如操作系统内核、嵌入式系统固件),也可以用于构建高性能的应用层服务(如 Web 服务器、数据库、命令行工具),甚至编译到 WebAssembly 在浏览器中运行。它的应用范围非常广泛。
Rust 的核心优势
理解 Rust 的价值,关键在于其独特的核心优势:
1. 内存安全,无 GC
这是 Rust 最引人注目的特性。传统的内存安全通常依赖垃圾回收器在运行时自动管理内存。GC 虽然方便,但会带来不可预测的停顿(Stop-the-world),这在对延迟要求极高的场景是不可接受的。
Rust 通过其 所有权系统(Ownership System) 在编译时保证内存安全。每个值都有一个变量作为其所有者(owner)。同一时刻,一个值只有一个所有者。当所有者超出作用域时,值将被丢弃(drop
)。这种规则消除了双重释放(double free)和使用已释放内存(use after free)的错误。
配合所有权系统的是 借用(Borrowing) 和 生命周期(Lifetimes)。
* 借用 允许你通过引用(reference)访问数据,而无需转移所有权。Rust 的借用规则是:在任意给定时间,你只能拥有一个可变引用(&mut T
)或任意数量的不可变引用(&T
),不能同时拥有可变引用和不可变引用。这些规则在编译时强制执行,防止了数据竞争。
* 生命周期 是编译器用来确保所有借用都是有效的、不会出现悬垂引用(dangling reference)的概念。它描述了引用的有效范围。在大多数情况下,编译器可以自动推断生命周期,你无需手动标注。
这套系统可能初看起来有些复杂,但一旦掌握,它将极大地提高代码的可靠性,因为许多运行时错误被提前到了编译阶段。
2. 零成本抽象(Zero-Cost Abstractions)
Rust 提供了许多高级抽象,如迭代器(Iterators)、泛型(Generics)、特征(Traits)。这些抽象在源代码层面提升了开发效率和代码可读性,但在编译后的机器码中几乎不会带来额外的运行时开销。这意味着你可以使用高级抽象,同时获得 C/C++ 级别的性能。
3. 性能卓越
由于没有垃圾回收的开销,且对底层硬件有精细控制,Rust 代码的性能通常可以与 C/C++ 相媲美。编译器(rustc)基于 LLVM,具有强大的优化能力。
4. 并发无忧(Fearless Concurrency)
Rust 的所有权和借用系统天然地解决了并发编程中的一大难题——数据竞争。Rust 在编译时检查,确保多个线程不能同时以不安全的方式访问同一块数据。它通过 Send
和 Sync
这两个标记 trait 来保证线程安全的数据传递和共享。遵循 Rust 的并发编程范式,你可以自信地编写多线程代码,而不用担心常见的数据竞争问题。
5. 可靠性高
Rust 强大的类型系统、强制性的错误处理(通过 Result<T, E>
和 Option<T>
)以及详尽的模式匹配(Pattern Matching)共同提高了代码的可靠性。它鼓励你显式地处理所有可能的错误情况,而不是依赖容易被忽略的空指针或异常。
6. 强大的工具链和友好的生态
Rust 拥有一个现代化的、一体化的工具链,最核心的是 Cargo。Cargo 是 Rust 的构建系统和包管理器,类似于 Java 的 Maven/Gradle、Node.js 的 npm/yarn、Python 的 pip。使用 Cargo,你可以轻松创建新项目、构建代码、运行测试、生成文档以及管理依赖。
Rust 的生态系统(crates.io)也在快速发展,提供了大量高质量的库(crates),涵盖了 Web 开发、数据库、网络、加密、数据科学、嵌入式等众多领域。
7. 优秀的文档和社区
Rust 拥有非常高质量的官方文档,特别是《The Rust Programming Language》(通常称为“The Book”),这是一本优秀的入门教材,而且已经被翻译成多种语言,包括高质量的中文版本。此外,Rust 社区非常活跃和友好,提供了各种学习资源和帮助。
Rust 的核心概念解析
要真正理解 Rust,需要深入了解几个核心概念:
1. 所有权 (Ownership)
所有权是 Rust 最独特、也是理解难度最大的概念。它是一组规则,用于管理程序如何使用内存,而无需垃圾回收器。
核心规则:
* 每个值都有一个变量作为其所有者。
* 同一时刻,一个值只能有一个所有者。
* 当所有者(变量)离开作用域时,值会被丢弃(drop),释放其占用的资源。
示例:
“`rust
fn main() {
let s1 = String::from(“hello”); // s1 拥有 String 值 “hello”
let s2 = s1; // s1 的所有权转移给 s2。现在 s1 无效!
// println!(“{}”, s1); // 编译错误:借用了移动后的值 s1
let s3 = s2.clone(); // deep copy,s2 和 s3 各自拥有不同的数据
println!("s2 = {}, s3 = {}", s2, s3); // s2 和 s3 都有效
// 当 main 函数结束时,s3 和 s2 (以及底层的堆数据) 被丢弃。
} // s3 和 s2 在这里离开作用域。
``
String
这里的类型存储在堆上,默认情况下,赋值操作是移动(move),即所有权转移。对于存储在栈上的基本类型(如整数、浮点数、布尔值、字符等),它们实现了
Copy` trait,赋值操作是复制(copy),不会发生所有权转移。
2. 借用 (Borrowing)
借用允许你临时访问一个值,而无需获取其所有权。这是通过引用来实现的。引用就像一个指针,指向某个值在内存中的位置。
核心规则(借用检查器 enforce):
* 在任意给定时间,你只能拥有:
* 一个可变引用 (&mut T
)
* 或者 任意数量的不可变引用 (&T
)
* 你不能同时拥有可变引用和不可变引用。
* 引用必须始终有效(不能是悬垂引用)。
示例:
“`rust
fn calculate_length(s: &String) -> usize { // s 是对 String 的不可变借用
s.len()
} // s 在这里离开作用域。但因为它不拥有 String,所以什么也不会被丢弃。
fn change_string(s: &mut String) { // s 是对 String 的可变借用
s.push_str(“, world!”);
} // s 在这里离开作用域。
fn main() {
let mut s = String::from(“hello”); // s 是可变的
let len = calculate_length(&s); // 借用 s,不可变
println!("The length of '{}' is {}.", s, len); // s 仍然有效,因为只是借用
change_string(&mut s); // 借用 s,可变
println!("s is now: {}", s); // s 仍然有效
// 尝试同时创建多个借用会触发编译错误:
// let r1 = &s; // 不可变借用
// let r2 = &s; // 不可变借用 (允许)
// let r3 = &mut s; // 可变借用 (不允许与 r1/r2 同时存在)
// println!("{}, {}, {}", r1, r2, r3); // 编译错误
}
“`
借用规则防止了同一时间多个部分修改同一数据造成的混乱和数据竞争。
3. 生命周期 (Lifetimes)
生命周期是 Rust 编译器用来确保引用不会悬垂(指向已释放内存)的概念。它们是引用的有效作用域。生命周期注解(通常以 '
开头,如 'a
)用于告诉编译器不同引用的生命周期之间的关系,尤其是在函数签名或结构体定义中,当编译器无法确定引用是否有效时。
示例:
“`rust
// 这个函数接受两个字符串切片,返回其中较长的一个。
// ‘a 是生命周期参数,表示返回的引用和输入的两个引用具有相同的生命周期,
// 即返回的引用不会比输入的任何一个引用“活”得更久。
fn longest<‘a>(x: &’a str, y: &’a str) -> &’a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from(“abcd”);
let string2 = “xyz”;
let result = longest(string1.as_str(), string2); // string1.as_str() 和 string2 都是 &'static str 或 `'a`
println!("The longest string is {}", result); // result 的生命周期由 string1 和 string2 的生命周期共同决定
}
“`
大多数时候,Rust 编译器能够自动推断生命周期,你无需手动标注。只有在涉及函数参数和返回值或结构体字段的引用,并且生命周期关系复杂到编译器无法确定时,才需要手动注解。
4. 特质 (Traits)
特质是 Rust 定义共享行为的方式,类似于其他语言中的接口(Interface)或类型类(Type Class)。一个特质定义了一组方法签名,任何实现了这个特质的类型都必须提供这些方法的实现。
示例:
“`rust
// 定义一个 Summarizable 特质
trait Summarizable {
fn summarize(&self) -> String; // 方法签名
}
// 为 NewsArticle 类型实现 Summarizable 特质
struct NewsArticle {
headline: String,
location: String,
author: String,
content: String,
}
impl Summarizable for NewsArticle {
fn summarize(&self) -> String {
format!(“{}, by {} ({})”, self.headline, self.author, self.location)
}
}
// 为 Tweet 类型实现 Summarizable 特质
struct Tweet {
username: String,
content: String,
reply: bool,
retweet: bool,
}
impl Summarizable for Tweet {
fn summarize(&self) -> String {
format!(“{}: {}”, self.username, self.content)
}
}
fn notify(item: &impl Summarizable) { // 参数接受实现了 Summarizable 特质的任何类型
println!(“Breaking news! {}”, item.summarize());
}
fn main() {
let article = NewsArticle {
headline: String::from(“Penguins win the Stanley Cup!”),
location: String::from(“Pittsburgh, PA”),
author: String::from(“Iceburgh”),
content: String::from(“The Pittsburgh Penguins once again won the Stanley Cup.”),
};
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
notify(&article); // article 实现了 Summarizable
notify(&tweet); // tweet 实现了 Summarizable
}
“`
特质是 Rust 实现多态(Polymorphism)和泛型约束的核心机制。它们使得你可以编写能够处理多种不同类型数据的通用代码。
5. 错误处理 (Error Handling)
Rust 没有传统的异常(Exceptions)机制。它采用更函数式、更显式的方式处理可恢复错误,使用 Result<T, E>
枚举;对于不可恢复的程序错误,则使用 panic!
宏。
-
Option<T>
: 一个枚举,表示一个值可能存在(Some(T)
)或不存在(None
)。类似于其他语言中的可空类型或 null,但更安全,因为你必须显式地处理None
的情况。 -
Result<T, E>
: 一个枚举,表示一个操作可能成功并返回一个值(Ok(T)
)或失败并返回一个错误(Err(E)
)。这是 Rust 处理可恢复错误的主要方式。你需要显式地检查返回值是Ok
还是Err
。
示例:
“`rust
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let greeting_file_result = File::open(“hello.txt”);
let greeting_file = match greeting_file_result {
Ok(file) => file, // 如果成功,获取文件句柄
Err(error) => match error.kind() { // 如果失败,检查错误类型
ErrorKind::NotFound => match File::create("hello.txt") { // 文件不存在,尝试创建
Ok(fc) => fc, // 创建成功,返回文件句柄
Err(e) => panic!("Problem creating the file: {:?}", e), // 创建失败,panic
},
other_error => panic!("Problem opening the file: {:?}", other_error), // 其他错误,panic
},
};
// 更简洁的方式,使用 ? 操作符 (仅能在返回 Result 或 Option 的函数中使用)
// fn read_username_from_file() -> Result<String, io::Error> {
// let mut username_file = File::open("username.txt")?; // ? 自动处理 Ok/Err
// let mut username = String::new();
// username_file.read_to_string(&mut username)?;
// Ok(username)
// }
}
“`
这种显式的错误处理模式提高了代码的健壮性,因为你被迫思考并处理所有可能的失败情况。
Rust 入门指南:动手实践
理论说再多,不如亲手实践。让我们开始安装 Rust 并编写第一个程序。
1. 安装 Rust
Rust 的安装通常通过 rustup
工具链安装器进行。rustup
可以管理不同版本的 Rust 编译器(rustc
)、Cargo、以及其他工具,并支持交叉编译。
访问 Rust 官方网站 https://www.rust-lang.org/zh-CN/tools/install
,按照指引下载并运行安装脚本。
在 Linux 或 macOS 上,打开终端并运行:
bash
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
按照提示操作。安装完成后,可能需要重启终端或执行 source $HOME/.cargo/env
命令来更新环境变量。
在 Windows 上,下载 rustup-init.exe
并运行。它提供了控制台安装和图形界面安装选项。推荐使用默认设置进行安装。
安装完成后,验证是否安装成功:
bash
rustc --version
cargo --version
如果能正确显示版本信息,说明安装成功。
2. 你的第一个 Rust 程序 (Hello, World!)
Rust 的项目通常使用 Cargo 进行管理。我们使用 Cargo 来创建一个新的项目。
打开终端,进入你希望创建项目的目录,然后运行:
bash
cargo new hello_rust
cd hello_rust
这会在当前目录下创建一个名为 hello_rust
的文件夹,其中包含一个基本的 Rust 项目结构:
hello_rust/
├── .gitattributes
├── .gitignore
├── Cargo.toml
└── src/
└── main.rs
* Cargo.toml
: 项目的清单文件,包含项目信息、依赖等。
* src/main.rs
: 项目的源代码入口点。
打开 src/main.rs
文件,你会看到 Cargo 已经为你生成了一个经典的 Hello, World! 程序:
rust
fn main() {
println!("Hello, world!");
}
* fn main()
: 定义了一个名为 main
的函数。在 Rust 中,main
函数是所有可执行程序的入口点。
* println!
: 这是一个 Rust 的宏(macro),用于在控制台输出文本。Rust 宏的名称后面通常带有一个感叹号 !
,与普通函数区分。宏在编译时展开成代码。
现在,我们来编译并运行这个程序。在 hello_rust
项目的根目录下(也就是 Cargo.toml
文件所在的目录),运行:
bash
cargo run
cargo run
命令会先编译你的代码(如果需要),然后运行生成的可执行文件。你应该会在终端看到输出:
Compiling hello_rust v0.1.0 (~/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in X.XXs
Running `target/debug/hello_rust`
Hello, world!
恭喜!你已经成功运行了第一个 Rust 程序。
如果你只想编译代码而不运行,可以使用 cargo build
命令。生成的可执行文件会放在 target/debug/
目录下。
3. 使用 Cargo 管理项目
Cargo 是 Rust 开发的基石,掌握它非常重要。
- 创建新项目:
cargo new <project_name>
- 构建项目:
cargo build
(生成 debug 版本,在target/debug/
) - 构建发布版本:
cargo build --release
(生成优化后的 release 版本,在target/release/
,速度更快但编译时间长) - 运行项目:
cargo run
- 检查代码 (不编译):
cargo check
(速度很快,用于快速检查语法和类型错误) - 运行测试:
cargo test
(Rust 的测试直接写在源代码文件中或单独的测试文件中) - 生成文档:
cargo doc
(生成 HTML 文档,在target/doc/
) - 格式化代码:
cargo fmt
(需要安装rustfmt
组件:rustup component add rustfmt
) - 检查代码风格和潜在错误:
cargo clippy
(需要安装clippy
组件:rustup component add clippy
) - 添加依赖: 在
Cargo.toml
的[dependencies]
部分手动添加,然后 Cargo 会在构建时自动下载和管理。例如,要使用一个名为rand
的随机数库,你可以在Cargo.toml
中添加:
toml
[dependencies]
rand = "0.8.5" # 使用 rand 库的 0.8.5 版本
保存Cargo.toml
后,再次运行cargo build
或cargo run
,Cargo 会自动下载rand
库。
Rust 的生态系统 (Crates.io)
Rust 的库称为crate。官方的包注册中心是 crates.io
(https://crates.io/
)。你可以在上面搜索各种 Rust 库,并在你的 Cargo.toml
文件中将其添加为依赖。
一些常见领域的流行 crate:
* Web 框架: actix-web
, rocket
, warp
, axum
* 异步编程: tokio
, async-std
* 命令行解析: clap
, structopt
(已合并到 clap v3+
)
* 序列化/反序列化: serde
* 数据库驱动: diesel
(ORM), sqlx
(异步)
* 文件系统操作: dunce
, fs_extra
* 并发工具: crossbeam
, rayon
* 图形界面 (GUI): iced
, egui
, winit
(窗口管理)
通过 crates.io
和 Cargo,你可以轻松地在你的项目中使用社区贡献的各种功能。
如何学习 Rust?
Rust 的学习曲线通常被认为比带有 GC 的语言(如 Python、Go)要陡峭,尤其是在理解所有权、借用和生命周期方面。但这门语言绝对值得投入时间。
以下是一些推荐的学习资源:
-
《Rust 程序设计语言》(The Rust Programming Language):
这是官方出品的入门书籍,被认为是学习 Rust 的最佳起点。它详细介绍了 Rust 的各种概念,并提供了大量示例。强烈推荐阅读高质量的中文翻译版本。 你可以在线免费阅读:https://rustbyexample.com/
(注意这不是官方书,官方书链接在下方)。
官方书中文版在线阅读:https://book.rust-lang.org/chinese/title-page.html
-
Rust By Example (Rust 范例):
一个通过一系列可运行代码示例来介绍 Rust 概念的网站。对于通过代码学习的人来说非常有用。
中文版在线阅读:https://rustbyexample.com/chinese/
-
Rustlings:
一个通过完成小型练习来帮助你熟悉 Rust 语言的开源项目。非常适合动手实践,可以帮助你克服编译错误并理解常见的 Rust 语法和概念。
GitHub 地址:https://github.com/rust-lang/rustlings
-
Rust 社区:
加入 Rust 相关的论坛、聊天群组(如 Discord)、邮件列表或本地技术社区。提问并参与讨论是解决学习中遇到的困难的有效方式。
学习建议:
- 保持耐心:不要因为初期的编译错误而气馁。Rust 编译器非常严格,但它给出的错误信息通常非常有帮助。把编译错误看作是编译器在指导你写出更安全、更可靠的代码。
- 理解核心概念:花时间真正理解所有权、借用和生命周期。这是掌握 Rust 的关键。可以多画图、多实践来加深理解。
- 动手实践:从小项目开始,逐步尝试实现更复杂的功能。例如,可以尝试编写一个简单的命令行工具、一个文件处理脚本或一个网络客户端。
- 阅读代码:阅读一些优秀的 Rust 开源项目的源代码,学习它们的设计思路和编码风格。
- 利用工具:充分利用 Cargo、
rustfmt
、clippy
等工具来提高开发效率和代码质量。
谁在使用 Rust?
Rust 已经被许多知名公司和项目采用,用于开发关键组件:
- 操作系统: Linux 内核(部分模块)、 Redox OS、Tock (嵌入式)
- Web 基础设施: Cloudflare (网络服务), Firefox (部分组件), Dropbox (后端服务), Linkerd (Service Mesh)
- 数据库: TiKV (分布式 Key-Value 数据库)
- 区块链: Solana, Polkadot, Near Protocol 等许多公链使用 Rust
- 大型科技公司内部: Google (Android 和其他项目)、Microsoft (Azure 和 Windows 部分组件)、Meta (Facebook)、Amazon (AWS)
- 命令行工具: bat, fd, exa 等许多高性能工具
这表明 Rust 不仅仅是一个学术研究项目,它已经在工业界得到了广泛的认可和应用。
挑战与注意事项
虽然 Rust 充满优势,但也有一些挑战:
- 学习曲线:如前所述,所有权和借用系统需要时间去理解和适应。
- 编译时间:相比一些解释型语言或 JIT 语言,Rust 的编译时间可能较长,尤其是在大型项目或初次构建时(但
cargo check
速度很快,可以弥补部分效率)。 - 生态系统成熟度:虽然发展迅速,但在某些特定领域,Rust 的库可能不如 Java、Python、Node.js 等老牌语言生态那样丰富或成熟。但这正在快速改善。
结论
Rust 是一门具有 혁신성(创新性)和 前景(前景)的语言。它在不牺牲性能的前提下,从语言层面解决了困扰开发者多年的内存安全和并发数据竞争问题。虽然学习曲线可能有所挑战,但它所带来的代码可靠性、性能优势以及由强大工具链和友好社区提供的生产力提升,使得 Rust 成为构建下一代高性能、高可靠性软件的有力选择。
对于中文开发者而言,现在正是入门 Rust 的好时机。丰富的中文学习资源和日益壮大的本地社区将为你提供支持。
如果你正在寻找一门能够提升你在系统编程、高性能计算、安全开发或新兴技术(如 WebAssembly、区块链)领域能力的语言,Rust 绝对值得你投入时间和精力去探索。拿起你的键盘,安装 rustup
,开始你的 Rust 之旅吧!
祝你在 Rust 的世界里探索愉快,构建出色的软件!