Rust 知识图谱的基础部分围绕核心语法、内存安全机制、数据结构与控制流展开
一、Rust 语言概述
Rust 是一门系统编程语言,由 Mozilla 开发(2010 年启动,2015 年发布 1.0 稳定版),设计目标是内存安全、高性能、并发安全。其核心特性包括:
- 内存安全:通过所有权(Ownership)、借用(Borrowing)、**生命周期(Lifetimes)**机制,在编译期避免空指针、数据竞争等内存错误;
- 高性能:与 C/C++ 相当,无垃圾回收(GC) overhead;
- 并发安全:所有权模型确保线程安全,无需手动加锁;
- 零成本抽象:高级语法(如 trait、泛型)不引入运行时性能损失。
Rust 适用于系统编程(操作系统、嵌入式)、高性能服务端、WebAssembly、区块链等场景。
二、基础语法
1. 变量与可变性
- 不可变变量:默认情况下,变量不可变(值无法修改),需用 let 声明:let x = 5; // 不可变,x = 6 会报错
- 可变变量:用 mut 关键字声明,值可修改:let mut y = 5;
y = 6; // 合法 - 常量:用 const 声明,必须指定类型,值在编译期确定:const MAX_NUM: u32 = 100; // 常量,不可修改
- 变量遮蔽(Shadowing):允许用同一名称重新声明变量(类型可改变),区别于 mut(仅值可变):let x = 5;
let x = x + 1; // 遮蔽,x 变为 6(类型仍为 i32)
let x = "hello"; // 再次遮蔽,x 变为字符串(类型改变)
2. 数据类型
Rust 是静态类型语言(编译期需确定类型),分为标量类型(单一值)和复合类型(多个值组合)。
(1)标量类型
- 整型:表示整数,分为有符号(i8/i16/i32/i64/i128/isize)和无符号(u8/u16/u32/u64/u128/usize),默认类型为 i32(最快)。
- isize/usize:依赖架构(32 位系统为 32 位,64 位为 64 位),主要用于数组索引、指针运算。
- 字面值:支持十进制(98_222)、十六进制(0xff)、八进制(0o77)、二进制(0b111_000),可加后缀(如 57u8)或用 _ 分隔(如 1_000)。
- 浮点型:表示小数,分为 f32(单精度)和 f64(双精度),默认类型为 f64(精度更高,速度与 f32 相近)。
- 布尔型:bool,取值为 true 或 false,用于条件判断。
- 字符型:char,表示 Unicode 标量值(如 'A'、'中'、'😊'),占 4 字节,用单引号声明。
(2)复合类型
- 元组(Tuple):将多个不同类型的值组合成一个类型,长度固定。
- 定义:let tup = (500, 6.4, 'J');(类型 (i32, f64, char));
- 访问:用模式匹配解构(let (x, y, z) = tup;)或索引(tup.0,索引从 0 开始)。
- 数组(Array):存储相同类型的固定长度集合,分配在栈上(而非堆)。
- 定义:let a = [1, 2, 3, 4, 5];(类型 [i32; 5]);
- 访问:用索引(a[0]),若索引超出范围,Rust 会panic(避免越界访问)。
三、核心特性:所有权与借用
Rust 的内存安全核心机制,无需 GC 即可避免内存泄漏、悬垂指针等问题。
1. 所有权规则
- 唯一所有者:每个值有且仅有一个所有者(变量);
- 作用域释放:所有者离开作用域时,值会被自动释放(调用 drop 函数);
- 所有权转移:当值被赋值给另一个变量时,所有权会转移(原变量失效)。
示例:let s1 = String::from("hello"); // s1 拥有字符串所有权
let s2 = s1; // 所有权转移给 s2,s1 失效(无法再使用)
// println!("{}", s1); // 报错:s1 已失效
2. 借用与引用
- 不可变借用:用 & 声明,允许多个引用同时访问值,但不能修改:let s = String::from("hello");
let r1 = &s; // 不可变借用
let r2 = &s; // 多个不可变借用合法
println!("{} {}", r1, r2); // 合法 - 可变借用:用 &mut 声明,一次只能有一个可变引用,且不能与不可变引用共存(避免数据竞争):let mut s = String::from("hello");
let r3 = &mut s; // 可变借用
r3.push_str(", world"); // 合法(修改值)
// let r4 = &s; // 报错:不可变引用与可变引用共存
3. 生命周期
生命周期是引用的有效范围,确保引用始终指向有效内存。Rust 编译器通过生命周期注解(如 'a)检查引用的有效性,避免悬垂指针(如返回局部变量的引用)。
示例:
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s1.len() > s2.len() { s1 } else { s2 }
}
上述函数中,'a 表示 s1、s2 和返回值的生命周期一致,确保返回的引用不会超过输入引用的有效范围。
四、控制流
Rust 支持常见的控制流结构,其中**if 是表达式**(返回值),循环用于重复执行代码。
1. if 表达式
- 条件无需括号,必须为 bool 类型;
- 可返回值(最后一个表达式的值),无需 return。
示例:let number = 10;
let result = if number > 5 {
"大于5" // 表达式,返回值
} else {
"小于等于5"
};
println!("{}", result); // 输出:大于5
2. 循环
- loop:无限循环,需用 break 退出(可返回值):let mut counter = 0;
let result = loop {
counter += 1;
if counter == 5 {
break counter * 2; // 返回 10
}
};
println!("{}", result); // 输出:10 - while:条件为真时执行循环体:let mut n = 3;
while n > 0 {
println!("{}", n); // 输出 3、2、1
n -= 1;
} - for:遍历集合(如数组、范围),最常用:for i in 1..=5 { // 范围 1~5(包含 5)
println!("{}", i); // 输出 1、2、3、4、5
}
// 遍历数组
let arr = [10, 20, 30];
for num in arr.iter() {
println!("{}", num); // 输出 10、20、30
}
3. match 表达式
match 是 Rust 的模式匹配工具,用于匹配值并执行对应逻辑,必须覆盖所有可能的情况( exhaustive )。
示例:
enum Direction { Up, Down, Left, Right }
let dir = Direction::Up;
match dir {
Direction::Up => println!("向上"),
Direction::Down => println!("向下"),
_ => println!("其他方向"), // 通配符,覆盖剩余情况
}
五、函数
函数是 Rust 程序的基本构建块,用 fn 关键字声明。
1. 函数定义
- 语法:fn 函数名(参数: 类型) -> 返回值类型 { 函数体 };
- 参数必须指定类型(Rust 不支持类型推断的参数);
- 返回值:函数体最后一个表达式的值(无分号),或用 return 提前返回。
示例:fn add(a: i32, b: i32) -> i32 {
a + b // 最后一个表达式,返回值(无分号)
}
fn main() {
let result = add(3, 5);
println!("{}", result); // 输出:8
}
2. 语句与表达式
- 语句:执行操作但不返回值(如 let x = 5;、函数定义);
- 表达式:计算并返回值(如 a + b、if 表达式、循环)。
示例:let x = 5; // 语句(无返回值)
let y = { // 代码块(表达式),返回最后一个表达式的值
let a = 3;
a + 2 // 返回值 5(无分号)
};
println!("{}", y); // 输出:5
六、错误处理
Rust 没有异常机制,用**Result和Option**枚举处理错误。
1. Option 枚举
Option<T> 表示“有值”(Some(T))或“无值”(None),用于处理可能缺失的值。
示例:
fn get_first_element(arr: &[i32]) -> Option<i32> {
if arr.is_empty() {
None // 无值
} else {
Some(arr[0]) // 有值
}
}
let arr = [10, 20, 30];
match get_first_element(&arr) {
Some(val) => println!("第一个元素:{}", val), // 输出:10
None => println!("数组为空"),
}
2. Result 枚举
Result<T, E> 表示“成功”(Ok(T))或“失败”(Err(E)),用于处理可恢复的错误(如文件读取失败)。
示例:
use std::fs::File;
fn read_file(path: &str) -> Result<String, std::io::Error> {
let file = File::open(path)?; // ? 操作符:若出错,返回 Err
let content = std::io::read_to_string(file)?;
Ok(content) // 成功,返回 Ok(content)
}
fn main() {
match read_file("test.txt") {
Ok(content) => println!("文件内容:{}", content),
Err(e) => println!("错误:{}", e),
}
}
七、结构体与枚举
1. 结构体(Struct)
结构体是自定义数据类型,用于将多个相关值组合成一个类型(类似 C 的结构体)。
- 定义:struct 结构体名 { 字段名: 类型, … };
- 实例化:用 { 字段名: 值, … } 初始化;
- 方法:用 impl 块定义,可访问结构体字段。
示例:struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
impl User {
// 关联函数(类似构造函数)
fn new(username: String, email: String) -> User {
User {
username,
email,
sign_in_count: 0,
active: true,
}
}
// 方法(&self 表示不可变引用)
fn get_username(&self) -> &str {
&self.username
}
}
fn main() {
let user = User::new(String::from("alice"), String::from("alice@example.com"));
println!("用户名:{}", user.get_username()); // 输出:alice
}
2. 枚举(Enum)
枚举是多 variant 类型,用于表示“多种可能的情况”(类似 C 的枚举,但更强大)。
- 定义:enum 枚举名 { Variant1, Variant2, … };
- variant 可携带数据(如 IpAddrKind::V4(String))。
示例:enum IpAddr {
V4(String), // IPv4 地址(字符串)
V6(String), // IPv6 地址(字符串)
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let work = IpAddr::V6(String::from("::1"));
// 模式匹配处理枚举
match home {
IpAddr::V4(addr) => println!("IPv4:{}", addr), // 输出:127.0.0.1
IpAddr::V6(addr) => println!("IPv6:{}", addr),
}
总结
Rust 知识图谱的基础部分涵盖:
- 语言概述:定位、特性与应用场景;
- 基础语法:变量、数据类型(标量/复合)、函数;
- 核心机制:所有权、借用、生命周期(内存安全的关键);
- 控制流:if、loop、while、for、match;
- 错误处理:Option、Result;
- 数据结构:结构体、枚举。
这些内容是学习 Rust 的基石,后续的泛型、trait、并发等高级特性均基于此展开。建议通过实践(如编写小项目、解决 LeetCode 题)巩固基础,逐步深入理解 Rust 的设计思想。
