Skip to content
📖 Auto 版 Rust Book本书目录

I/O 项目:构建命令行程序 ​

本章回顾了你到目前为止学到的许多技能,并探索了标准库的 I/O 功能。我们将构建一个命令行工具 —— 我们自己的 grep 版本 —— 来练习前面章节中的概念。

我们的 minigrep 项目将结合:

  • 用 type 和 ext 组织代码([第 7 章][ch7])
  • 使用 List<T> 和 String([第 8 章][ch8])
  • 用 !T 和 .collect() 处理错误([第 9 章][ch9])
  • 使用 spec([第 10 章][ch10])
  • 编写测试([第 11 章][ch11])

接受命令行参数 ​

使用 env.args() 读取命令行参数:

使用 `env.args()` 读取命令行参数

env.args() 返回命令行参数的迭代器。第一个参数始终是程序名本身。要收集它们到 List 中:

auto
let args = env.args().collect()

注意:如果任何参数包含无效的 Unicode,env.args() 会 panic。 对于可能包含无效 Unicode 的参数,请使用 env.args_os()。

读取文件 ​

通过 use.rust 使用 Rust 标准库的 fs.read_to_string():

通过命令行参数读取文件

要点:

  • fn main() ! — ! 返回类型启用错误传播
  • fs.read_to_string(file_path).! — 读取文件,通过 .collect() 传播错误
  • use env 和 use.rust std::fs — 导入环境和文件系统模块

重构以提高模块化 ​

随着程序增长,我们将逻辑提取到单独的函数和 Config 类型中。这遵循了将二进制(main.rs)和库(lib.rs)代码分离的关注点分离惯例。

提取 Config 类型 ​

模块化的 minigrep,包含 Config 类型和 search 函数

这个重构展示了几个重要的模式:

  1. type Config — 将配置值分组到一个类型中
  2. Config.build() 返回 !Config — 在错误情况下使用 throw
  3. fn run(config Config) ! — 将程序逻辑与设置分离
  4. fn main() ! — 保持简洁:构建配置、运行、处理错误
  5. .collect() 用于 !T — 等价于 Rust 的 ? 运算符

环境变量 ​

环境变量让用户无需更改命令行参数即可配置行为。使用 env.var("VAR_NAME"),它返回 !String:

环境变量实现大小写不敏感搜索

env.var("IGNORE_CASE") 返回 !String。.is_ok() 方法检查环境变量是否已设置(不管其值如何),返回 bool。

设置环境变量后运行:

console
$ IGNORE_CASE=1 automan run -- to poem.txt

写入标准错误 ​

使用 eprint() 输出错误消息(等价于 Rust 的 eprintln!):

auto
eprint("Error: file not found")

这会将输出发送到 stderr 而非 stdout,这样用户可以将成功输出重定向到文件,同时仍然在屏幕上看到错误消息:

console
$ automan run -- query file.txt > results.txt

I/O 速查 ​

操作AutoRust
命令行参数env.args()std::env::args()
读取文件fs.read_to_string(path).!std::fs::read_to_string(path)?
环境变量env.var("KEY")std::env::var("KEY")
检查环境变量env.var("KEY").is_ok()std::env::var("KEY").is_ok()
标准输出print()println!()
标准错误eprint()eprintln!()
退出码sys.exit(code)std::process::exit(code)

总结 ​

本章演示了用 Auto 构建一个完整的命令行程序:

  1. 用 env.args() 接受命令行参数
  2. 用 use.rust std::fs 和 fs.read_to_string() 读取文件
  3. 用 type Config 和分离的 search/run 函数 组织代码
  4. 用 !T 返回类型和 .collect() 传播 处理错误
  5. 用 env.var() 使用环境变量
  6. 用 eprint() 写入标准错误

该项目结合了前面每一章的概念:类型、扩展、集合、错误处理、spec、泛型和测试。

在下一章中,我们将探索函数式语言特性:闭包和迭代器。

基于 MIT 许可发布。