Rust 的诞生与历史
从一次电梯故障说起
2006 年,Mozilla 工程师 Graydon Hoare 住在公寓里,某天电梯坏了。他发现电梯控制软件崩溃了——而这类嵌入式系统通常用 C 或 C++ 编写。崩溃的根源往往是内存安全问题:一个悬垂指针、一次越界访问,就可能让整个程序崩溃。他思考:为什么 2006 年了,我们还在被这类问题困扰?
这个念头促使他开始了一个业余项目——设计一门新的系统编程语言,它要能像 C 一样高效,像现代语言一样安全。这就是 Rust 的起点。
关键时间线
谁在用 Rust?
Rust 已经从小众语言成长为工业级选择:
- Linux 内核:自 6.1 版本起,Rust 成为继 C 之后第二种官方支持的内核开发语言
- 微软 Windows:Azure 云基础设施、Windows 11 部分核心组件已用 Rust 重写
- 谷歌 Android:新版 Android 中约 21% 的新代码用 Rust 编写
- Mozilla Firefox:Servo 布局引擎、Firefox 内置的 WebRender 渲染引擎
- Cloudflare:边缘计算平台 Workers,替代了原来的 JavaScript V8 隔离
- Discord:将数百万用户的 Read States 服务从 Go 迁移到 Rust,延迟从 500ms 降至 1ms
Rust 的核心设计哲学
三大承诺
Rust 的设计目标可以用三个词概括:安全(Safe)、快速(Fast)、并发(Concurrent)。更准确的说法是:
内存安全,不需要 GC:通过所有权系统在编译期保证,不产生运行时开销。
零成本抽象:你使用的高级抽象(泛型、迭代器等)编译后的代码和手写底层代码一样高效。
无畏并发:类型系统防止数据竞争,让你在编译期发现并发错误,而不是在生产环境崩溃。
与其他语言的对比
| 特性 | C/C++ | Go | Java/Python | Rust |
|---|---|---|---|---|
| 内存管理 | 手动 malloc/free | 垃圾回收 GC | 垃圾回收 GC | 所有权系统(编译期) |
| 内存安全 | 不保证 | 基本保证 | 保证 | 编译期完全保证 |
| 运行时开销 | 极低 | GC 暂停 | GC + JVM 开销 | 极低(无 GC) |
| 数据竞争 | 运行时出现 | 基本防止 | 运行时出现 | 编译期防止 |
| 抽象能力 | 中等 | 较强 | 强 | 强(零成本) |
| 学习曲线 | 中等 | 平缓 | 平缓 | 陡峭 |
为什么 Rust 学习曲线陡峭?
Rust 的难点不在于语法,而在于所有权系统——这是一套你在其他语言中从未接触过的概念体系。当你写 let y = x; 时,在大多数语言里是简单的赋值或引用复制,但在 Rust 中可能意味着所有权的转移,之后再使用 x 会导致编译错误。
这种"与编译器搏斗"的初期体验是真实的,但一旦你理解了所有权系统,你会发现编译器是你最好的队友——它在代码运行之前就替你找出了所有潜在的内存问题。
安装开发环境
rustup:官方工具链管理器
rustup 是 Rust 官方提供的工具链版本管理器,类似于 Node.js 生态中的 nvm。它负责安装和管理不同版本的 Rust 编译器、标准库和工具。
# macOS / Linux:一行安装
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Windows:下载并运行 rustup-init.exe
# 访问 https://rustup.rs 获取安装程序
# 安装完成后,重新加载 shell 配置(或重启终端)
source $HOME/.cargo/env
# 验证安装
rustc --version # rustc 1.77.0 (aedd173a2 2024-03-17)
cargo --version # cargo 1.77.0 (ef5e5bba6 2024-03-15)
rustup --version # rustup 1.27.0 (bbb9276d2 2024-03-08)
管理 Rust 版本
# 更新到最新稳定版
rustup update
# 安装 nightly 工具链(用于实验性特性)
rustup install nightly
# 为特定项目设置工具链
rustup override set nightly
# 查看已安装的工具链
rustup toolchain list
# 添加编译目标(例如 WebAssembly)
rustup target add wasm32-unknown-unknown
日常开发请始终使用稳定版工具链。nightly 版包含未稳定的特性,API 可能随时变化,只在需要特定实验性功能时才切换。
Cargo:Rust 的构建工具与包管理器
Cargo 是什么?
Cargo 是 Rust 的官方构建系统和包管理器,它一体化地处理了:依赖下载与版本管理、代码编译、测试运行、文档生成、代码发布。在其他语言生态中,这些职责往往分散在多个工具中(如 npm + webpack + jest),而 Cargo 将它们统一起来,大大降低了工程配置复杂度。
创建第一个项目
# 创建新的二进制(可执行)项目
cargo new hello_rust
cd hello_rust
# 创建新的库项目
cargo new my_lib --lib
# 项目目录结构
hello_rust/
├── Cargo.toml # 项目清单:名称、版本、依赖
├── Cargo.lock # 依赖锁定文件(类似 package-lock.json)
└── src/
└── main.rs # 程序入口
Cargo.toml 解析
[package]
name = "hello_rust"
version = "0.1.0"
edition = "2024" # Rust Edition,影响某些语法行为
authors = ["Your Name <you@example.com>"]
description = "My first Rust project"
[dependencies]
# 格式:crate_name = "版本号"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
[dev-dependencies]
# 仅用于测试和基准测试的依赖
assert_cmd = "2.0"
[[bin]]
# 如果项目有多个可执行文件,在这里声明
name = "hello"
path = "src/main.rs"
常用 Cargo 命令
cargo build # 编译(debug 模式)
cargo build --release # 编译(release 模式,开启优化)
cargo run # 编译并运行
cargo run -- --args # 传递命令行参数
cargo test # 运行所有测试
cargo doc --open # 生成并打开文档
cargo check # 只检查语法错误,不生成可执行文件(最快)
cargo clippy # 运行 lint 检查
cargo fmt # 格式化代码
cargo add serde # 添加依赖到 Cargo.toml
cargo update # 更新依赖版本
cargo build 默认使用 debug 模式:编译快,但不开启优化,二进制文件包含调试符号,体积大、运行慢。
cargo build --release 使用 release 模式:编译慢(开启全部优化),但运行速度可比 debug 快 10-100 倍,适合生产部署。
代码质量工具
rustfmt:代码格式化
Rust 社区有一套统一的代码风格规范,rustfmt 负责自动执行格式化,消除团队内的代码风格争论。
# 格式化当前项目所有文件
cargo fmt
# 只检查格式问题,不修改文件(CI 中使用)
cargo fmt -- --check
# 配置文件(放在项目根目录)
# rustfmt.toml
max_width = 100
tab_spaces = 4
edition = "2024"
clippy:Rust 代码检查器
Clippy 是 Rust 官方提供的 lint 工具,包含超过 700 条检查规则,能发现代码中的常见错误模式、性能问题、以及不符合 Rust 惯用法的代码。
# 运行 clippy
cargo clippy
# 将警告视为错误(CI 中推荐使用)
cargo clippy -- -D warnings
# clippy 示例:它会检查这类代码
// 不好的写法:clippy 会建议改进
let v: Vec<i32> = Vec::new(); // clippy 建议用 vec![]
if v.len() == 0 { } // clippy 建议用 v.is_empty()
let x = &*v; // clippy 建议去掉多余的 &*
// 允许特定 lint(在代码中标注)
#[allow(clippy::needless_pass_by_value)]
fn process(data: String) { }
IDE 与编辑器支持
Hello, World! 详解
第一个 Rust 程序
// src/main.rs
fn main() {
println!("Hello, World!");
}
这几行代码虽然简单,但包含了 Rust 的几个重要特征:
fn是定义函数的关键字,main是程序的入口函数println!末尾的感叹号表示这是一个宏(macro),不是普通函数。宏在编译期展开,功能比函数更灵活- Rust 用花括号
{}作为代码块边界,语句以分号;结尾 - 缩进约定是 4 个空格(由 rustfmt 强制执行)
格式化输出
fn main() {
let name = "Rust";
let year = 2015;
// {} 是默认格式化占位符
println!("Hello, {}! 诞生于 {} 年。", name, year);
// {:?} 用于调试输出(需要实现 Debug trait)
let arr = [1, 2, 3];
println!("数组:{:?}", arr);
// {:#?} 美化调试输出
println!("美化输出:{:#?}", arr);
// 命名参数
println!("{lang} 是系统编程语言", lang = "Rust");
// 格式化数字
println!("{:.2}", 3.14159); // 保留两位小数: 3.14
println!("{:08b}", 42); // 二进制,宽度8位: 00101010
println!("{:x}", 255); // 十六进制: ff
}
println! 输出后自动添加换行符,print! 不添加。还有 eprintln! 和 eprint! 用于输出到标准错误流(stderr)。