Rust 学习笔记 20:项目实战二:构建 grep 命令行工具 (minigrep)

Rust 学习笔记 20:项目实战二:minigrep “UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.” – Dennis Ritchie 到目前为止,我们已经学习了 Rust 的大部分核心特性。现在,让我们把它们串起来,复刻一个经典的命令行工具:grep。 我们的目标是创建一个 minigrep,它接受一个查询字符串和一个文件名,然后打印出文件中包含查询字符串的行。 1. 需求分析 用法: 1$ cargo run -- searchstring example-filename.txt 功能点: 读取命令行参数。 读取文件内容。 筛选包含关键词的行。 错误处理(用户没传参数?文件不存在?)。 关注点分离:main.rs 负责处理参数和系统调用,lib.rs 负责核心逻辑。 TDD:测试驱动开发。 环境变量:支持 IGNORE_CASE=1 进行大小写不敏感搜索。 2. 核心代码演进 我们将代码分为 main.rs 和 lib.rs。 2.1 参数解析与配置 在 src/lib.rs 中定义 Config 结构体: 1use std::env; 2 3pub struct Config { 4 pub query: String, 5 pub file_path: String, 6 pub ignore_case: bool, 7} 8 9impl Config { 10 pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> { 11 args.next(); // 也就是程序名,通常忽略 12 13 let query = match args.next() { 14 Some(arg) => arg, 15 None => return Err("Didn't get a query string"), 16 }; 17 18 let file_path = match args.next() { 19 Some(arg) => arg, 20 None => return Err("Didn't get a file path"), 21 }; 22 23 let ignore_case = env::var("IGNORE_CASE").is_ok(); 24 25 Ok(Config { 26 query, 27 file_path, 28 ignore_case, 29 }) 30 } 31} 注意这里使用了 impl Iterator,这样我们可以直接消费 env::args(),更加高效。 ...

2025-11-04 · 2 min · 344 words · 老墨

[GoLang避坑实战-11] 万物皆 Reader:像老鸟一样玩转 Go 语言的 IO 流

大家好,我是极客老墨。 在很多语言里,文件操作和网络操作是两套完全不同的 API。但在 Go 语言里,无论你是读文件、读网络请求,还是读一段内存字符串,你面对的通常都是同一个东西:io.Reader。 这种**“万物皆 Reader”**的设计哲学,是 Go 语言简洁高效的灵魂所在。这篇我们就来深度拆解 Go 的 IO 体系,让你不仅会用,还能写出高性能的 IO 代码。 1. 核心基石:Reader 与 Writer 接口 Go 的 IO 体系建立在两个极简的接口之上: 1type Reader interface { 2 Read(p []byte) (n int, err error) 3} 4 5type Writer interface { 6 Write(p []byte) (n int, err error) 7} 为什么这两个接口牛逼? 因为它屏蔽了底层实现。只要一个类型实现了 Read 方法,它就是 Reader。你可以把一个“读取文件”的 Reader 直接传给一个“处理 HTTP 响应”的函数。 老墨避坑指南: Read 方法里有个细节——io.EOF。它表示“文件结束”,虽然它是一个 error 类型,但在逻辑处理中,它通常标志着读取成功的终点,而不是程序出错了。所以处理时要先看 n > 0 处理数据,再看 err == io.EOF 退出循环。 ...

2025-06-19 · 2 min · 371 words · 老墨

Rust 学习笔记 10:项目实战一:猜数字

Rust 学习笔记 10:项目实战一:猜数字 “Programming is not about typing, it’s about thinking.” 之前的 9 篇笔记,我们一直在抠语法细节。 今天是圣诞节(假设),我们来点轻松的:用 Rust 写一个猜数字游戏。 规则很简单: 程序生成一个 1~100 的随机数。 玩家输入猜测。 程序提示 “大了”、“小了” 或 “猜对了”。 猜对了游戏结束,否则继续。 1. 引入依赖 Crates Rust 的标准库很精简,没有内置随机数生成。我们需要引入第三方库 rand。 修改 Cargo.toml: 1[dependencies] 2rand = "0.9" 这和 Go 的 go get 不太一样,Rust 更像是 Node.js 的 npm,依赖管理非常现代化。 2. 获取用户输入 1use std::io; 2 3let mut guess = String::new(); // 创建可变空字符串 4 5io::stdin() 6 .read_line(&mut guess) // 传可变引用进去修改 7 .expect("Failed to read line"); // 处理 Result::Err 注意那个 read_line 返回的是 io::Result 枚举。如果读取失败,它会返回 Err,expect 方法会帮你 panic 并打印错误信息。在 Rust 中,忽略返回值是会被警告的。 ...

2024-12-25 · 2 min · 249 words · 老墨