type
Post
date
Nov 5, 2025
slug
Rust/notebook/12
summary
学习下 Rust 圣经,记录笔记
status
Published
tags
Rust
category
技术茶点
icon
password
概括前面学到的知识并探索更多的标准库功能。
核心内容是:
- 构建一个命令行工具:将使用 Rust 来构建一个自己的经典命令行搜索工具
grep(用于在文件中搜索指定字符串)。
- 练习 I/O 交互:学习如何与文件和命令行输入/输出进行交互。
- 高级命令行功能:涵盖读取命令行参数、读取文件、处理环境变量和将错误信息输出到标准错误流(
stderr)等。
这个项目将结合并练习之前章节中学到的代码组织、Vector 和字符串、错误处理、Trait 和生命周期、以及测试等概念。
12.一个 I/O 项目:构建命令行程序
12.1.接受命令行参数
概念 | 含义 | 关键点 |
获取命令行参数 | 使用 Rust 标准库中的 std::env::args() 来获取传给程序的参数。 (Rust 文档) | |
参数顺序与程序名 | 第一个参数 args[0] 是程序自身的路径或名称,后续参数是用户传入的。 (Rust 文档) | 所以如果你期望两个参数,通常是 args[1] 和 args[2] 分别代表你定义的“查询字符串”“文件路径”等。 |
示例:读取指定两个参数 | 示例代码中: rust<br>let args: Vec<String> = env::args().collect();<br>let query = &args[1];<br>let file_path = &args[2]; (Rust 文档) | |
无足够参数的风险 | 建议后续章节中加入参数数量检查 + 返回错误或提示用户。 | |
Unicode/操作系统差异 | 在跨平台或非 UTF-8 环境时需注意。 |
12.2.读取文件
概念 | 含义 | 关键点 |
读取文件内容 | let contents = fs::read_to_string(file_path).expect("…"); — 最简写法。 (Rust 文档) | |
处理错误 | 文件读取返回 Result<String, std::io::Error>,需要处理或断言。 (Rust 文档) | 临时代码里可用 expect(),但生产代码应更完整处理。 |
使用 File::open + read_to_string 方法 | 更显式地打开文件句柄、读出内容,再合并为字符串。 (Massachusetts Institute of Technology) | 示例: rust<br>let mut f = File::open(filename).expect("file not found");<br>let mut contents = String::new();<br>f.read_to_string(&mut contents).expect("error reading file"); |
模块引入 | 需要 use std::fs; 或 use std::fs::File; use std::io::prelude::*; 等。 (Massachusetts Institute of Technology) | 方便之后函数调用,无需全路径。 |
项目结构与样例输入 | 建议在项目根目录放置测试文件,比如 poem.txt,用于验证读取逻辑。 (Rustの日本語ドキュメント/Japanese Docs for Rust) | 在命令行中传入该文件路径为参数,测试读取功能。 |
改进空间 | 提前考虑结构可提高项目可维护性。 |
12.3.重构以改进模块化与错误处理
概念 | 含义 | 关键点 |
模块化结构(Separation of Concerns) | 将项目中不同职责(如:解析命令行、配置构建、读取文件、搜索逻辑、错误处理)拆分成不同模块/函数。 (Rust 文档) | |
配置结构体(Config struct) | 用结构体封装程序需要的配置变量(如搜索词、文件路径、是否忽略大小写),比直接使用多个独立变量更清晰。 (Rust 文档) | 这样代码可读性更强,后续扩展也更方便。 |
改进错误处理 | 例如 run(config) -> Result<(), Box<dyn Error>>,在 main 中处理 Err(e) 并退出。 | |
统一错误处理入口 | 将错误处理逻辑集中在 main 中,使程序结构清晰,易于维护。 (Massachusetts Institute of Technology) | 这样未来维护或变更时,只需在一个地方调整错误处理方式。 |
提炼函数 & 测试友好 | 测试逻辑不在 main 中,而在 lib.rs 内部函数,从而提升测试覆盖与可维护性。 |
12.4.采用测试驱动开发完善库的功能
概念 | 含义 | 关键点 |
测试驱动开发 (TDD) | 先编写一个失败的测试 → 编写最少量代码让其通过 → 重构代码 → 重复。 (Massachusetts Institute of Technology) | 这种流程有助于确保库的核心功能被覆盖并持续保持正确。 |
将逻辑从 main 提取至 lib | 这样测试不依赖命令行调用,而是直接调用函数,更快捷、稳定。 | |
为新功能编写测试 | 比如新增 search(query, contents) -> Vec<&str> 函数,先写测试 ASSERT 出期待结果。 (Rust 文档) | 示例中:搜索 “duct” 在文本中只返回包含该词的那一行。 |
代码实现使测试通过 | 按步骤:遍历每行 → 检查是否包含查询 → 将匹配行推入返回列表 → 返回。 (Rust 文档) | 一步步从测试失败到成功,再重构。 |
使用生命周期参数 | 函数签名示例: fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str>。 | |
将被测试功能整合进程序运行逻辑 | 用于 CLI 程序如 minigrep query filename 的最终运行效果。 |
12.5.处理环境变量
概念 | 含义 | 关键点 |
环境变量(Environment Variables) | 程序运行时,可由操作系统/用户在 shell 中设置的键-值对,用于控制程序行为。 (doc.rust-lang.org) | 在本例中,程序通过环境变量 IGNORE_CASE 来决定是否进行不区分大小写的搜索。 (doc.rust-lang.org) |
读取环境变量 | 使用标准库模块 std::env::var("VAR_NAME") 来查询某个环境变量。 (rust-book.cs.brown.edu) | 返回 Result<String, std::env::VarError>,表示变量是否已设置。 |
将环境变量与逻辑关联 | 程序读取变量是否 已设置 (不用关心具体值),然后将其作为配置项决定程序行为。 (doc.rust-lang.org) | 例如: let ignore_case = env::var("IGNORE_CASE").is_ok(); 表示如果 IGNORE_CASE 已设置,则 ignore_case = true。 (rust-book.cs.brown.edu) |
环境变量 vs 命令行参数 | 环境变量适用于“用户不想每次输入但希望一次设置多次使用”的场景;命令行参数适合“每次运行可变”场景。 (doc.rust-lang.org) | 在设计 CLI 程序时,可混用参数和环境变量,并决定优先级。 (rust-book.cs.brown.edu) |
跨平台注意 | 不同操作系统或 shell 设置环境变量的语法可能不同。 (doc.rust-lang.org) | 如在 Linux/macOS: IGNORE_CASE=1 cargo run -- query filename;在 Windows PowerShell 可能 $Env:IGNORE_CASE=1; cargo run -- query filename。 (Rustの日本語ドキュメント/Japanese Docs for Rust) |
12.6.将错误信息输出到标准错误而不是标准输出
概念 | 含义 | 关键点 |
stdout vs stderr | 在命令行工具中,标准输出(stdout)用于正常结果输出;标准错误(stderr)用于输出错误或诊断信息。 (doc.rust-lang.org) | 如果只重定向 stdout(用 >),但错误信息也通过 stdout 输出,则会被输到文件,而不是显示在屏幕上。 |
为何使用 stderr 输出错误 | 这样用户可以把正常结果重定向到文件,但仍然在屏幕看到错误信息;符合 Unix/CLI 工具惯例。 (doc.rust-lang.org) | 常见场景: cargo run > output.txt 若错误通过 stderr 输出,屏幕会显示错误而 output.txt 只含正常结果。 |
如何在 Rust 中写入 stderr | 使用 eprintln!() 宏,它会把格式化信息写到 stderr。 (Massachusetts Institute of Technology) | 例如: eprintln!("Problem parsing arguments: {err}"); |
更手动方式写入 stderr | 若需更控制或旧版 Rust,可用 writeln!(&mut std::io::stderr(), …) 写入 stderr。 (itfanr.gitbooks.io) | 例如: let mut stderr = std::io::stderr(); writeln!(&mut stderr, "Error: {}", err).expect("Could not write to stderr"); |
在项目中的典型应用时机 | 当程序解析命令行参数失败、读取文件失败、运行逻辑错误时,用 stderr 输出错误并退出;正常运行结果用 stdout 输出。 (doc.rust-lang.org) | 在 main() 中:若 Config::build 返回错误,则 eprintln!() 并 process::exit(1);否则继续运行并把结果通过 println!() 输出。 |
- Author:沈林曦
- URL:https://blog.aibhtt.com/article/Rust/notebook/12
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts












