使用标准库构建 CLI
不引入第三方 clap 时,用 std::env 与 std::io 构建可测试的小型 CLI 闭环。
#type / howto
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
使用标准库构建 CLI
目标
完成一个仅依赖标准库的 CLI:解析参数、读文件或 stdin、错误用非零退出语义、核心逻辑可单测。
这个场景为什么出现
很多内部工具不需要完整解析器;先掌握 std::env::args 与纯函数拆分,再上 clap。
[!abstract] 一句话理解
main只做参数与 I/O;纯逻辑放库函数;用退出码与 stderr 表达失败。
最小可运行示例
场景:统计文件字节数的 mini wc -c
use std::env;
use std::fs;
use std::process;
// 业务意图:CLI 统计文件字节数。
// 教学点:args;错误到 stderr;纯函数 count_bytes 可测。
fn count_bytes(data: &[u8]) -> usize {
data.len()
}
fn main() {
let mut args = env::args().skip(1);
let Some(path) = args.next() else {
eprintln!("usage: bytecount <file>");
process::exit(2);
};
match fs::read(&path) {
Ok(bytes) => println!("{}", count_bytes(&bytes)),
Err(e) => {
eprintln!("error reading {path}: {e}");
process::exit(1);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts_len() {
assert_eq!(count_bytes(b"abc"), 3);
}
}
建议运行:
cargo run -- /etc/hosts
cargo test
结合场景再看三个关注点
- 退出码区分用法错误与运行错误
- 逻辑可测
- 后续可换成 clap 而不改 count_bytes
核心步骤
- 定义用户故事与退出码
- 拆纯函数
args/stdin/fs- 测试 +
--help文案(手写)
工程实践
本节总结
- std 足够做小 CLI
- 纯逻辑与 I/O 分离
- 退出码契约
自测题
- 为什么核心逻辑不要直接读 env?
- 用法错误常用退出码?
参考答案
- 便于测试与复用。
- 常见 2(惯例,可团队约定)。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — I/O Project | 官方书 | CLI 项目 |
| std::env | 标准库 | 参数与环境 |