跳到主要内容

Rust 编程教程

欢迎学习 Rust 编程语言!本教程将带你从零基础开始,逐步掌握 Rust 的核心知识和技能。

什么是 Rust?

Rust 是一门系统编程语言,由 Mozilla 研发,专注于安全性、并发性和性能。它具有以下特点:

  • 内存安全:通过所有权系统在编译时保证内存安全,无需垃圾回收
  • 零成本抽象:高级抽象不会带来运行时开销
  • 并发安全:编译器在编译时检测数据竞争
  • 高性能:性能媲美 C/C++
  • 实用性强:丰富的标准库和活跃的社区

为什么学习 Rust?

  1. 内存安全无需 GC:Rust 独特的所有权系统让它在保证内存安全的同时不牺牲性能
  2. 并发编程友好:编译器帮助你避免并发错误
  3. 行业需求增长:系统编程、WebAssembly、嵌入式开发等领域需求旺盛
  4. 优秀的开发体验:友好的编译器错误提示、强大的包管理器 Cargo
  5. 活跃的社区:丰富的第三方库(crates)和完善的学习资源

Rust 的应用场景

系统编程

  • 操作系统内核
  • 设备驱动
  • 嵌入式系统

Web 开发

  • WebAssembly 应用
  • 后端服务(使用 Actix、Rocket 等框架)
  • Web 服务器

命令行工具

  • 现代化的 CLI 工具(如 ripgrep、bat、exa)
  • 构建工具

网络服务

  • 高性能代理服务器
  • 分布式系统
  • 微服务

游戏开发

  • 游戏引擎
  • 游戏逻辑

区块链

  • 智能合约
  • 区块链客户端

Rust 核心概念

所有权(Ownership)

所有权是 Rust 最独特的特性,它让 Rust 在没有垃圾回收器的情况下保证内存安全。

fn main() {
let s1 = String::from("hello"); // s1 拥有字符串的所有权
let s2 = s1; // 所有权从 s1 转移到 s2
// println!("{}", s1); // 错误!s1 不再有效

println!("{}", s2); // 正确
}

解释

  • Rust 中每个值都有一个所有者(owner)
  • 同一时间只能有一个所有者
  • 所有者离开作用域时,值会被自动释放

借用和引用

使用引用可以访问数据而不获取所有权。

fn main() {
let s = String::from("hello");

let len = calculate_length(&s); // 借用 s

println!("字符串 '{}' 的长度是 {}", s, len);
}

fn calculate_length(s: &String) -> usize {
s.len()
} // s 是引用,离开作用域时不会释放数据

借用规则

fn main() {
let mut s = String::from("hello");

// 规则:要么有一个可变引用,要么有多个不可变引用
let r1 = &s; // 不可变引用
let r2 = &s; // 不可变引用
println!("{} {}", r1, r2);
// r1 和 r2 不再使用

let r3 = &mut s; // 可变引用(正确,因为 r1、r2 已不再使用)
r3.push_str(" world");
println!("{}", r3);
}

教程目录

基础阶段

进阶阶段

高级阶段

知识速查

  • 速查表 - Rust 常用语法和概念速查

学习建议

  1. 理解所有权:这是 Rust 最核心的概念,花时间彻底理解它
  2. 阅读编译器提示:Rust 编译器提供非常友好的错误信息
  3. 多写代码:Rust 的学习曲线较陡,实践是最好的老师
  4. 善用文档:使用 cargo doc 和官方文档
  5. 参与社区:Rust 社区非常友好,有问题可以积极提问

版本说明

本教程基于 Rust 1.85+Rust 2024 Edition 编写。

Rust 2024 Edition 完整变更列表

Rust 2024 Edition 是迄今为止最大的版本更新,以下是完整的变更列表:

语言变更

变更项说明
异步闭包支持 async || {} 语法定义异步闭包,以及 AsyncFnAsyncFnMutAsyncFnOnce trait
RPIT 生命周期捕获规则返回位置 impl Trait 现在默认捕获所有作用域内的泛型参数(包括生命周期),可使用 use<..> 显式指定
Unsafe extern 块extern 块现在必须使用 unsafe 关键字:unsafe extern "C" { ... }
Unsafe 属性#[export_name]#[link_section]#[no_mangle] 必须使用 #[unsafe(...)] 包装
禁止 static mut 引用static mut 的引用现在会产生编译错误,必须使用 addr_of!addr_of_mut!
unsafe 函数内操作unsafe_op_in_unsafe_fn lint 默认警告,unsafe fn 内部的 unsafe 操作需要显式 unsafe {}
if let 临时变量作用域if let 表达式中临时变量的作用域变更
尾表达式临时变量作用域块的尾表达式中临时变量的作用域变更
模式匹配保留禁止某些可能导致混淆的模式组合,为未来改进铺路
Never 类型回退变更改变 ! 类型的强制转换行为
宏片段说明符expr 片段现在也匹配 const_ 表达式
保留 gen 关键字为未来的生成器块保留 gen 关键字
保留语法保留 #"foo"# 风格字符串和 ## 标记

标准库变更

变更项说明
Prelude 扩展FutureIntoFuture 自动导入到 prelude
Box<[T]> IntoIteratorBox<[T]> 现在实现 IntoIterator
unsafe 函数std::env::set_varstd::env::remove_var 现在是 unsafe 函数
元组 trait元组支持 FromIteratorExtend(最多 12 个元素)

RPIT 生命周期捕获规则详解

RPIT(Return Position Impl Trait,返回位置 impl Trait)是 Rust 中一个重要的特性,它允许函数返回一个抽象类型。Rust 2024 Edition 对生命周期捕获规则进行了重要变更。

什么是生命周期捕获?

当一个函数返回 impl Trait 时,编译器需要知道这个 opaque type(不透明类型)可以使用哪些泛型参数。"捕获"一个泛型参数意味着这个参数可以在隐藏类型(hidden type)中使用。

Rust 2024 的变更

在 Rust 2024 之前,返回位置的 impl Trait 只捕获:

  • 所有类型参数和常量参数
  • 出现在 impl Trait 约束中的生命周期参数

从 Rust 2024 开始,默认捕获所有作用域内的泛型参数,包括生命周期参数:

// Rust 2021:不捕获 'a(因为 'a 没有出现在约束中)
fn f_2021<'a>(x: &'a ()) -> impl Sized {
// 等价于 impl Sized + use<>
*x // 错误!'a 未被捕获
}

// Rust 2024:自动捕获 'a
fn f_2024<'a>(x: &'a ()) -> impl Sized {
// 等价于 impl Sized + use<'a>
*x // 正确!'a 被自动捕获
}

使用 use<..> 显式指定捕获

可以使用 use<..> 语法显式控制捕获哪些参数:

// 显式捕获 'a 和 T
fn capture<'a, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> {
(x, y) // 可以使用 'a 和 T
}

// 不捕获任何参数
fn no_capture<'a, T>(x: &'a (), y: T) -> impl Sized + use<> {
42 // 返回固定值,不使用任何泛型参数
}

// 只捕获 T,不捕获 'a
fn capture_t_only<'a, T>(x: &'a (), y: T) -> impl Sized + use<T> {
y // 只使用 T
}

为什么要这个变更?

这个变更解决了之前开发者需要使用"技巧"来捕获生命周期的问题:

旧的"Captures 技巧"(Rust 2024 之前):

// 定义一个辅助 trait
trait Captures<T: ?Sized> {}
impl<T: ?Sized, U: ?Sized> Captures<T> for U {}

// 使用技巧捕获生命周期
fn old_style<'a, T>(x: &'a (), y: T) -> impl Sized + Captures<(&'a (), T)> {
(x, y)
}

Rust 2024+ 的简洁写法

fn new_style<'a, T>(x: &'a (), y: T) -> impl Sized {
(x, y) // 自动捕获 'a 和 T
}

迁移指南

运行 cargo fix --edition 可以自动处理大多数情况。如果需要保持旧行为,编译器会自动添加 use<> 约束:

// 迁移前(Rust 2021)
fn f<'a>(x: &'a ()) -> impl Sized { 42 }

// 自动迁移后(Rust 2024)
fn f<'a>(x: &'a ()) -> impl Sized + use<> { 42 }

迁移方式

cargo fix --edition

详细迁移指南请参考 Rust Edition Guide

参考资源

准备好开始学习了吗?点击下一章开始你的 Rust 编程之旅!