三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Rust 标准库 `std` 中最常用、最核心的模块和类型

Rust 标准库 `std` 中最常用、最核心的模块和类型

下面我将以零基础教学的视角,逐一讲述 Rust 标准库 std 中最常用、最核心的模块和类型。每一节我会说明:它是什么、为什么需要、怎么用、有哪些关键方法和常见例子,并尽量结合之前冒险者程序中的代码。


1. 预导入(Prelude)—— 自动给你准备的工具箱

在 Rust 里,每个程序都会自动导入一些最基本的东西,不需要你写 use std::...。它们包括:

  • Option::SomeOption::None
  • Result::OkResult::Err
  • VecStringBox
  • println!format!
  • CloneCopyDrop 等基础 trait

理解方式: 就像一盒你买来就能直接用的基础文具(铅笔、橡皮、尺子),不需要再专门申请。因此初学者最先接触的 OptionResultVec 等,都是预导入的,可以直接使用。


2. Option—— 可能没有值的“盒子”

Option 是一个枚举,代表一个值可能存在,也可能不存在。

enum Option<T> {Some(T),   // 有值None,      // 没有值
}

为什么需要? 在很多语言里,nullNone 常常导致崩溃。Rust 用 Option 强制你处理“没有值”的情况,从而避免空指针异常。

常用方法:

  • unwrap():如果有值就拿出来,没有值就崩溃(不要随意使用)。
  • expect("信息"):类似 unwrap,但可以自定义错误信息。
  • is_some() / is_none():判断是否有值。
  • matchif let:安全地取出值。

教学代码例子:

let secret = Some("宝藏");    // secret 是 Option<&str>,里面有 "宝藏"
match secret {Some(msg) => println!("{}", msg),None => println!("啥也没有"),
}

3. Result—— 操作可能失败

Result 也是枚举,专用于可能出错的操作。

enum Result<T, E> {Ok(T),    // 成功,带着结果 TErr(E),   // 失败,带着错误信息 E
}

为什么需要? 打开文件、网络连接、读取输入等都可能失败。Result 让你必须处理错误,否则编译不通过。

常用方法:

  • unwrap() / expect():成功拿值,失败则崩溃。
  • ? 运算符:如果成功就继续,失败就立刻把错误返回给上级函数。
  • is_ok() / is_err():判断是否成功。

教学代码例子:

fn use_item(&mut self, index: usize) -> Result<Item, GameError> {if index >= self.inventory.len() {return Err(GameError::NoItem);  // 返回错误}Ok(self.inventory.remove(index))    // 返回成功
}// 调用处用 match 处理
match hero.use_item(0) {Ok(item) => log!("使用物品: {}", item),Err(e)   => log!("错误: {}", e),
}

4. String 和 &str—— 存放文字的两种形式

  • &str(字符串切片):对一段 UTF-8 文本的“借用引用”,不能修改,通常是 "hello" 这种字面量。
  • String:拥有所有权的、可增长的字符串,可以修改和添加内容。

关键区别: &str 便宜、轻量,但无权修改;String 是独立的,可以随意增删改。

常用转换和方法:

  • "hello".to_string()String::from("hello"):字面量变 String。
  • push_str(" world"):追加切片。
  • push('!'):追加单个字符。
  • len():获取字节长度(UTF-8 下要注意中文多字节)。
  • as_str():得到 &str

教学代码中:

let name: &str = "千字文";             // 切片,借用
let s = "卷轴".to_string();           // String,拥有所有权
book_bag.add(s);                      // s 被移动进背包

5. Vec—— 动态数组

Vec<T> 是存放很多相同类型元素的列表,可自动增长。

创建和操作:

  • Vec::new():空向量。
  • vec![1,2,3]:宏快速创建。
  • .push(元素):在末尾加入。
  • .pop():移除末尾并返回 Option
  • .len():获取元素个数。
  • .get(index):安全索引,返回 Option<&T>
  • 直接 v[0] 索引会崩溃,推荐用 get

教学代码中:

let mut inventory: Vec<Item> = Vec::new();
inventory.push(Item::Sword(30));
// 迭代
for item in &inventory { ... }

6. 格式化:fmt 和 Display / Debug

std::fmt 模块提供了如何把各种类型变成字符串打印出来的 trait:

  • Debug:用于调试,用 {:?} 打印,几乎所有标准类型都实现了,也可用 #[derive(Debug)] 自动生成。
  • Display:用于用户友好的展示,用 {} 打印,需要手动实现。

教学代码中我们实现了 Display

impl fmt::Display for Item {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {match self {Item::Sword(atk) => write!(f, "剑(攻{})", atk),...}}
}

这样 println!("{}", item) 就会输出友好的文字。


7. Clone 与 Copy—— 如何复制值

  • Copy:轻量拷贝,比如整数、布尔,赋值时自动复制,原变量仍可使用。无法手动实现 Copy 的类型不能添加。
  • Clone:显式复制,调用 .clone(),适用于字符串、Vec 等复杂类型,会有性能开销。

教学意义: 初学者常困惑于所有权转移,Copy 类型不需要担心;非 Copy 类型要用 clone() 来深复制,如 s1.clone()


8. HashMap—— 键值对字典

std::collections::HashMap<K, V> 通过键快速查找值。

常用方法:

  • HashMap::new() 创建。
  • .insert(key, value) 插入。
  • .get(&key) 返回 Option<&V>
  • .entry(key).or_insert(value) 如果有键就返回其值,没有就插入并提供可变引用。

代码例子(未在教学代码中,但典型):

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert("Blue", 10);
let team_score = scores.get("Blue").unwrap_or(&0);

9. 智能指针:Box, Rc, Arc, RefCell

这些都是帮助管理内存和所有权的高级工具,但在零基础教学中先建立印象即可。

  • Box<T>:把数据放在堆上,比如解决递归类型的尺寸问题。简单理解:一个指向堆内存的指针,拥有数据。
  • Rc<T>:单线程引用计数,允许多个所有者共享数据,不可变引用。用 Rc::clone(&rc) 增加引用。
  • RefCell<T>:内部可变性,允许在只拥有不可变引用时修改内部值,但规则由编译时检查移到运行时,违规会 panic。
  • Arc<T>:线程安全的 Rc,用于多线程共享。
  • Mutex<T>:互斥锁,配合 Arc 可以安全地在多线程中修改同一份数据。

教学代码中:

// Rc + RefCell 让多个指针共享一个可变冒险者
let adv = Rc::new(RefCell::new(Adventurer::new("共享者")));
let adv2 = Rc::clone(&adv);
adv2.borrow_mut().health -= 10;   // 修改内部

10. 输入输出:io 模块

std::io 提供了 ReadWrite trait,以及标准输入 stdin()、标准输出 stdout()

最常用的是防止窗口闪退:

let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap(); // 等待用户输入回车

另外也包含 File 的读取,但 File 属于 std::fs,io 提供 Read trait。


11. 文件系统:fs 模块

std::fs 处理文件和目录。

常用:

  • File::open("路径"):打开文件,返回 Result<File>
  • read_to_string("路径"):一次性读取为字符串。
  • write("路径", 内容):写入文件。
  • create_dir("目录") 等。

教学代码中:

let mut file = File::open("adventure.toml")?;
let mut content = String::new();
file.read_to_string(&mut content)?;

12. 线程与同步:thread, Arc, Mutex, mpsc

  • std::thread::spawn(闭包):创建新线程。
  • move 闭包:强制移动所有权进线程。
  • handle.join().unwrap():等待线程结束。
  • Arc<Mutex<T>>:多线程共享可变数据。

教学代码:

let team = Arc::new(Mutex::new(vec![]));
let team2 = Arc::clone(&team);
thread::spawn(move || {team2.lock().unwrap().push("战友A".to_string());
}).join().unwrap();

13. 迭代器:iter 模块与 Iterator trait

迭代器是对数据序列进行操作的强大工具,来自 std::iter

核心方法:

  • .iter() / .iter_mut() / .into_iter() 获取迭代器。
  • .map(|x| ...) 转换每个元素。
  • .filter(|x| ...) 保留符合条件的元素。
  • .collect() 把迭代器变回集合。
  • .sum(), .count(), .find() 等消费者方法。

教学代码:

let strong: Vec<_> = items.iter().filter(|it| matches!(it, Item::Sword(a) if *a > 5)).collect();

14. 错误处理 trait:Error

std::error::Error 是所有错误类型的公共 trait,通常配合 Box<dyn Error> 使用,表示任意类型的错误。自定义错误只要实现了 DisplayDebug,再 impl Error for MyError {} 即可。

教学代码:

fn load_config(path: &str) -> Result<String, Box<dyn Error>> { ... }

15. 其他常用模块速览

  • std::env:获取环境变量、命令行参数 args()
  • std::process:运行外部命令,退出程序 exit()
  • std::timeDuration(时长)、Instant(时间点)。
  • std::cmpOrdering 枚举(Less, Equal, Greater),max/min 函数。
  • std::char:判断字符类型的方法。
  • std::mem:内存操作,如 swap, size_of

教学建议

对于零基础学习者,建议按照以下顺序逐步掌握:

  1. OptionResultString/&strVec(最常用)
  2. fmt::Display/DebugClone/Copy(打印与复制)
  3. HashMap(当需要字典时)
  4. BoxRcRefCell(理解所有权进阶)
  5. threadArcMutex(并发入门)
  6. fsio(文件操作)
  7. 迭代器方法链(map/filter/collect 等)

每学一个,都可以在冒险者程序里找到对应示例,通过阅读注释 + 运行程序 + 动手修改的方式,逐步把 Rust 的标准库用起来。

← 返回列表