外观
Rust 笔记
约 3801 字大约 13 分钟
2025-08-16
一、Rust 简介
1.1 什么是 Rust?
Rust 是一门系统级编程语言,专注于安全、并发和高性能。它由 Mozilla 研究院开发,现已成长为独立的开源项目。Rust 的设计目标是提供内存安全保证,同时不牺牲性能,使其成为系统编程的理想选择。
1.2 Rust 语言特点
- 高性能:Rust 速度惊人且内存利用率极高。没有运行时和垃圾回收,能胜任对性能要求特别高的服务,可以在嵌入式设备上运行。
- 内存安全:丰富的类型系统和所有权模型保证了内存安全和线程安全,让您在编译期就能消除各种各样的错误。
- 无畏并发:Rust 的所有权和类型系统确保了内存安全,这使得并发编程更加安全且无需垃圾收集器。
- 零成本抽象:高级抽象不会比直接使用底层代码有额外开销。
- 实用工具链:拥有出色的文档、友好的编译器和清晰的错误提示信息,集成了一流的工具(包管理器和构建工具)。
1.3 Rust 应用场景
- 系统编程:操作系统、文件系统、网络服务等
- WebAssembly:将 Rust 编译为 WebAssembly,用于高性能 Web 应用
- 网络服务:利用 Rust 的高性能和内存安全,构建可靠的服务端应用
- 嵌入式系统:资源受限环境下的应用开发
- 命令行工具:创建高性能、跨平台的 CLI 工具
二、开发环境搭建
2.1 安装 Rust
使用官方安装工具 rustup:
# Linux/macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Windows
# 下载并运行 rustup-init.exe 从 https://www.rust-lang.org/tools/install2.2 工具链介绍
- rustc:Rust 编译器
- cargo:Rust 的包管理器和构建系统(核心工具)
- rustup:Rust 工具链管理器
- rustfmt:代码格式化工具
- clippy:代码检查工具
2.3 创建第一个项目
# 创建二进制项目(可执行程序)
cargo new hello_world
# 创建库项目
cargo new mylib --lib
# 运行项目
cd hello_world
cargo run三、基础语法
3.1 变量与可变性
Rust 中的变量默认是不可变的,这是 Rust 安全性的基础之一。
fn main() {
let x = 5; // 不可变变量
println!("x = {}", x);
// x = 6; // 错误!不可变变量不能重新赋值
let mut y = 10; // 可变变量
y = 15; // 正确
println!("y = {}", y);
const MAX_POINTS: u32 = 100_000; // 常量,必须标注类型
println!("MAX_POINTS = {}", MAX_POINTS);
}变量遮蔽(Shadowing):Rust 允许声明相同名称的新变量,"遮蔽"之前的变量:
fn main() {
let x = 5;
let x = x + 1; // 遮蔽第一个 x
let x = x * 2; // 再次遮蔽
println!("x = {}", x); // 输出 12
}3.2 基本数据类型
标量类型
| 类型 | 描述 | 示例 |
|---|---|---|
| 整数 | ||
i8, i16, i32, i64, i128, isize | 有符号整数 | -128 to 127 (i8) |
u8, u16, u32, u64, u128, usize | 无符号整数 | 0 to 255 (u8) |
| 浮点数 | ||
f32, f64 | 浮点数 | 3.14, 2.0 |
| 布尔 | ||
bool | 布尔值 | true, false |
| 字符 | ||
char | Unicode 字符 | 'a', '中', '😊' |
fn main() {
// 整数
let decimal = 98_222; // 下划线可提高可读性
let hex = 0xff;
let octal = 0o77;
let binary = 0b1111_0000;
let byte = b'A'; // u8
// 浮点数
let x = 2.0; // f64
let y: f32 = 3.0; // f32
// 布尔
let t = true;
let f: bool = false;
// 字符
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
}复合类型
元组(Tuple):
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
// 解构
let (x, y, z) = tup;
println!("x = {}", x);
// 直接访问
let five_hundred = tup.0;
let six_point_four = tup.1;
let one = tup.2;
}数组(Array):
fn main() {
let a = [1, 2, 3, 4, 5]; // 类型自动推断
let months = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
let a: [i32; 5] = [1, 2, 3, 4, 5]; // 显式类型
let a = [3; 5]; // [3, 3, 3, 3, 3]
let first = a[0];
let second = a[1];
}3.3 注释与格式化
// 单行注释
/*
多行注释
可以跨越多行
*/
/// 文档注释,用于生成文档
///
/// # Examples
///
/// ```
/// let x = 5;
/// ```
fn main() {
// 格式化输出
println!("Hello, world!");
println!("{} days", 31);
println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
println!("{subject} {verb} {object}",
object="the lazy dog",
subject="the quick brown fox",
verb="jumps over");
// 调试输出
println!("{:?}", (12, "hi"));
}3.4 运算符
Rust 支持常见的运算符:
fn main() {
// 算术运算符
let sum = 5 + 10;
let difference = 95.5 - 4.3;
let product = 4 * 30;
let quotient = 56.7 / 32.2;
let remainder = 43 % 5;
// 布尔运算符
let t = true;
let f = false;
let and = t && f;
let or = t || f;
let not = !t;
// 比较运算符
let eq = 1 == 1;
let ne = 1 != 2;
let gt = 1 > 0;
let lt = 1 < 2;
let ge = 1 >= 1;
let le = 2 <= 3;
}四、控制流
4.1 条件语句
fn main() {
let number = 3;
// if 表达式
if number < 5 {
println!("条件为 true");
} else {
println!("条件为 false");
}
// 多条件分支
if number % 4 == 0 {
println!("能被 4 整除");
} else if number % 3 == 0 {
println!("能被 3 整除");
} else if number % 2 == 0 {
println!("能被 2 整除");
} else {
println!("不能被 4、3、2 整除");
}
// if 作为表达式
let condition = true;
let number = if condition { 5 } else { 6 };
println!("number 的值是:{}", number);
}4.2 循环语句
while 循环:
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
}for 循环(推荐使用):
fn main() {
// 遍历数组
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("值为: {}", element);
}
// 使用范围
for number in (1..4).rev() { // 3, 2, 1
println!("{}!", number);
}
println!("LIFTOFF!!!");
}loop 循环:
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // 带返回值的 break
}
};
println!("result = {}", result); // 20
}五、函数
5.1 函数定义与调用
// 函数定义
fn another_function(x: i32, y: i32) {
println!("x 的值为: {}", x);
println!("y 的值为: {}", y);
}
// 带返回值的函数
fn five() -> i32 {
5 // 表达式,不需要 return
}
fn main() {
another_function(5, 6);
let x = five();
println!("x 的值为: {}", x);
let y = plus_one(5);
println!("y 的值为: {}", y);
}
fn plus_one(x: i32) -> i32 {
x + 1 // 隐式返回
}5.2 语句与表达式
Rust 是基于表达式的语言:
- 语句(Statements):执行某些操作且没有返回值
- 表达式(Expressions):有计算步骤且有返回值
fn main() {
let x = 5; // 语句
let y = {
let x = 3;
x + 1 // 表达式,块的值
}; // 语句
println!("x 的值为: {}", x); // 5
println!("y 的值为: {}", y); // 4
}5.3 函数参数与返回值
// 多个参数
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("测量值: {}{}", value, unit_label);
}
// 返回元组
fn multiple_returns() -> (i32, i32) {
(5, 6)
}
fn main() {
print_labeled_measurement(5, 'h');
let (a, b) = multiple_returns();
println!("a = {}, b = {}", a, b);
}六、所有权与借用
6.1 所有权规则
Rust 所有权系统有三个基本原则:
- 每个值都有一个变量作为其所有者
- 值在同一时间只能有一个所有者
- 当所有者超出作用域时,值将被丢弃
fn main() {
{
let s = "hello"; // s 有效
} // s 超出作用域,内存被释放
let s1 = String::from("hello");
let s2 = s1; // s1 被移动到 s2,s1 无效
// println!("{}, world!", s1); // 错误!s1 已经无效
println!("{}, world!", s2);
}6.2 引用与借用
fn main() {
let s1 = String::from("hello");
// 不获取所有权,只借用
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
// &String 是对 String 的引用,不获取所有权
fn calculate_length(s: &String) -> usize {
s.len()
} // s 超出作用域,但因为没有所有权,所以不会释放任何内容可变引用:
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}借用规则:
- 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
- 引用必须始终有效
6.3 切片
切片允许你引用集合中一段连续的元素序列,而不需要引用整个集合。
fn main() {
let s = String::from("hello world");
// 字符串切片
let hello = &s[0..5];
let world = &s[6..11];
// 等价写法
let hello = &s[..5];
let world = &s[6..];
let all = &s[..];
// 数组切片
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);
}七、结构体与枚举
7.1 结构体
// 定义结构体
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
// 元组结构体
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
// 单元结构体
struct AlwaysEqual;
fn main() {
// 创建结构体实例
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
// 更新语法
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1 // 使用 user1 的其余字段
};
// 使用元组结构体
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}7.2 方法
impl User {
// &self 表示方法接收者,是 user1.say_hello() 中的 user1
fn say_hello(&self) {
println!("Hello, {}!", self.username);
}
// 可变引用
fn activate(&mut self) {
self.active = true;
}
// 关联函数(类似静态方法)
fn new(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
}
fn main() {
let mut user1 = User::new(
String::from("someone@example.com"),
String::from("someusername123")
);
user1.say_hello();
user1.activate();
}7.3 枚举
// 定义枚举
enum IpAddrKind {
V4,
V6,
}
// 枚举可以携带数据
enum IpAddr {
V4(String),
V6(String),
}
// 枚举可以携带不同类型的数据
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// 方法体
}
}
fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
let m = Message::Write(String::from("hello"));
m.call();
}7.4 match 控制流
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
// 带绑定的 match
fn match_with_binding(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
// 使用 _
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}八、错误处理
8.1 panic! 与不可恢复错误
fn main() {
// panic!("crash and burn");
let v = vec![1, 2, 3];
v[99]; // 索引越界,触发 panic
}8.2 Result 与可恢复错误
use std::fs::File;
use std::io::ErrorKind;
fn main() {
// 打开文件
let f = File::open("hello.txt");
let f = match f {
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),
},
other_error => {
panic!("Problem opening the file: {:?}", other_error)
}
},
};
// 更简洁的方式:unwrap 和 expect
let f = File::open("hello.txt").unwrap(); // 如果是 Err,会 panic
let f = File::open("hello.txt").expect("Failed to open hello.txt");
}8.3 传播错误
use std::io;
use std::io::Read;
use std::fs::File;
// 传统方式
fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
// 使用 ? 运算符简化
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// 更简洁的写法
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}九、模块系统
9.1 模块定义
// src/lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {
// ...
}
fn seat_at_table() {
// ...
}
}
mod serving {
fn take_order() {
// ...
}
fn serve_order() {
// ...
}
fn take_payment() {
// ...
}
}
}
pub fn eat_at_restaurant() {
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径
front_of_house::hosting::add_to_waitlist();
}9.2 use 关键字
// 将路径引入作用域
use crate::front_of_house::hosting;
// 或
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
// 重命名
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// ...
}
fn function2() -> IoResult<()> {
// ...
}9.3 pub use 重新导出
// 在库中
pub mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
// 在外部代码中
use restaurant::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}十、常用集合类型
10.1 Vector
fn main() {
// 创建
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
// 添加元素
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
// 访问元素
let third: &i32 = &v[2];
println!("第三个元素是 {}", third);
match v.get(2) {
Some(third) => println!("第三个元素是 {}", third),
None => println!("没有第三个元素"),
}
// 遍历
for i in &v {
println!("{}", i);
}
// 修改遍历
let mut v = vec![1, 2, 3, 4, 5];
for i in &mut v {
*i += 50;
}
}10.2 String
fn main() {
// 创建
let s = String::new();
let data = "initial contents";
let s = data.to_string();
let s = "initial contents".to_string();
let s = String::from("initial contents");
// 更新
let mut s = String::from("foo");
s.push_str("bar");
let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
println!("s2 is {}", s2); // s2 仍然有效
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 注意 s1 被移动了,不再有效
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3); // 不会获取所有权
// 索引
let s1 = String::from("hello");
let h = &s1[0..1]; // Rust 字符串不支持直接索引
// 遍历
for c in "नमस्ते".chars() {
println!("{}", c);
}
for b in "नमस्ते".bytes() {
println!("{}", b);
}
}10.3 HashMap
use std::collections::HashMap;
fn main() {
// 创建
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// 从元组创建
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
// 访问
let team_name = String::from("Blue");
let score = scores.get(&team_name);
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
// 更新
scores.insert(String::from("Blue"), 25); // 替换
scores.entry(String::from("Yellow")).or_insert(50); // 不存在则插入
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
}十一、泛型与特质
11.1 泛型
// 泛型函数
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("最大数字是 {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("最大字符是 {}", result);
}
// 泛型结构体
struct Point<T> {
x: T,
y: T,
}
// 泛型枚举
enum Result<T, E> {
Ok(T),
Err(E),
}11.2 Trait
Trait 定义了类型应当实现的行为:
// 定义 trait
pub trait Summary {
fn summarize(&self) -> String;
// 默认实现
fn summarize_author(&self) -> String {
format!("(Read more from {}...)", self.summarize())
}
}
// 实现 trait
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
// 重写默认实现
fn summarize_author(&self) -> String {
format!("@{}", self.username)
}
}
fn main() {
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
}11.3 Trait Bound
// 使用 trait bound 限制泛型
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// 多个 trait bound
pub fn notify<T: Summary + Display>(item: &T) {
// ...
}
// where 子句(更清晰)
pub fn notify<T>(item: &T)
where
T: Summary + Display,
{
// ...
}
// 返回实现了 trait 的类型
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}十二、实用技巧与最佳实践
12.1 Cargo 常用命令
# 创建新项目
cargo new project_name
# 构建项目
cargo build
# 构建并运行
cargo run
# 检查代码(不生成二进制文件)
cargo check
# 发布构建(优化)
cargo build --release
# 运行测试
cargo test
# 生成文档
cargo doc --open
# 添加依赖
cargo add package_name
# 更新依赖
cargo update12.2 错误处理最佳实践
- 对于可能失败的操作,使用
Result<T, E>而不是panic! - 使用
?运算符简化错误传播 - 为自定义错误类型实现
std::error::Errortrait - 使用
thiserror或anyhow库简化错误处理
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Parse error: {0}")]
Parse(#[from] std::num::ParseIntError),
#[error("Custom error: {message}")]
Custom { message: String },
}12.3 代码格式化与检查
- 使用
cargo fmt格式化代码(需要安装rustfmt) - 使用
cargo clippy进行代码检查(需要安装clippy)
# 安装 rustfmt
rustup component add rustfmt
# 安装 clippy
rustup component add clippy
# 格式化代码
cargo fmt
# 运行 clippy
cargo clippy12.4 常用标准库模块
// 文件操作
use std::fs;
use std::io::{self, Read, Write};
// 命令行参数
use std::env;
// 错误处理
use std::error::Error;
// 多线程
use std::thread;
use std::sync::{Mutex, Arc};
// 网络
use std::net;