使用标准库构建 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

结合场景再看三个关注点

  1. 退出码区分用法错误与运行错误
  2. 逻辑可测
  3. 后续可换成 clap 而不改 count_bytes

核心步骤

  1. 定义用户故事与退出码
  2. 拆纯函数
  3. args/stdin/fs
  4. 测试 + --help 文案(手写)

工程实践

  • 大工具转 clap
  • 配置见 配置管理
  • 日志别滥用 println 到 stdout 污染管道

本节总结

  • std 足够做小 CLI
  • 纯逻辑与 I/O 分离
  • 退出码契约

自测题

  1. 为什么核心逻辑不要直接读 env?
  2. 用法错误常用退出码?
参考答案
  1. 便于测试与复用。
  2. 常见 2(惯例,可团队约定)。

延伸阅读与资料来源

资料类型支撑内容
The Book — I/O Project官方书CLI 项目
std::env标准库参数与环境
创建于 2026/7/15 更新于 2026/7/15