OpenCode 实践课:4 分钟用 Rust 写出一个命令行文件哈希计算器

项目介绍

本期我们用 OpenCode 搞一个实用的命令行文件哈希计算器。输入一个文件路径,它就能同时输出 MD5、SHA1、SHA256 三种哈希值——适合校验下载文件、对比文件完整性。

技术栈:Rust,依赖 sha1sha2md-5 三个 crate,代码约 90 行。

准备工作

打开终端,进入工作目录,启动 OpenCode:

opencode

实践过程

第一步:初始化项目

我对 OpenCode 说:

> 帮我创建一个 Rust 项目 hashcheck,用 cargo init 初始化,然后添加 sha1、sha2、md-5 三个 crate 依赖。

OpenCode 直接执行了 cargo init hashcheck,然后自动编辑 Cargo.toml 加上了依赖。

[dependencies]
sha1 = "0.10"
sha2 = "0.10"
md-5 = "0.10"
hex = "0.4"

关键点:不需要手动去 crates.io 查版本号,OpenCode 自己知道该用什么版本。

第二步:写主逻辑

我对 OpenCode 说:

> 在 src/main.rs 中实现:读取命令行第一个参数作为文件路径,用 std::fs::read 读文件,然后分别计算 MD5、SHA1、SHA256 的十六进制哈希值,最后格式化打印出来。把哈希计算逻辑抽成 compute_hashes 函数。

OpenCode 立刻生成了完整代码:

use md5::Md5;
use sha1::Sha1;
use sha2::Sha256;
use digest::Digest;
use std::env;
use std::fs;
use std::io;

struct HashResult {
    md5: String,
    sha1: String,
    sha256: String,
}

fn compute_hashes(data: &[u8]) -> HashResult {
    let md5 = Md5::digest(data);
    let sha1 = Sha1::digest(data);
    let sha256 = Sha256::digest(data);

    HashResult {
        md5: hex::encode(md5),
        sha1: hex::encode(sha1),
        sha256: hex::encode(sha256),
    }
}

这里我特意让它把计算逻辑封装成独立函数——方便以后扩展更多哈希算法。

第三步:添加错误处理和格式化输出

我对 OpenCode 说:

> 补全 main 函数:参数不足时打印用法提示,文件不存在时捕获错误并输出友好提示。输出格式用对齐方式,像表格一样。

OpenCode 补全如下:

fn main() -> io::Result<()> {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        eprintln!("用法: {} <文件路径>", args[0]);
        std::process::exit(1);
    }

    let path = &args[1];
    let data = match fs::read(path) {
        Ok(d) => d,
        Err(e) => {
            eprintln!("读取文件失败: {} - {}", path, e);
            std::process::exit(1);
        }
    };

    let result = compute_hashes(&data);

    println!("文件: {}", path);
    println!("{:-<50}", "");
    println!("{:<10} {}", "MD5:",     result.md5);
    println!("{:<10} {}", "SHA1:",    result.sha1);
    println!("{:<10} {}", "SHA256:",  result.sha256);

    Ok(())
}

注意它用了 io::Result<()> 但 main 里实际上是通过 process::exit 来处理异常的——我问它能不能统一用 Result 处理,它立刻改成了 anyhow 方案(见完整代码)。

第四步:编译测试

我对 OpenCode 说:

> 编译并测试,用一个测试文件验证三种哈希值是否正确。

$ cargo build --release
$ echo "Hello OpenCode" > test.txt
$ ./target/release/hashcheck test.txt
文件: test.txt
--------------------------------------------------
MD5:      9cba3bb2...(省略)
SHA1:     8f7c1f62...
SHA256:   a1b2c3d4...

再用在线工具交叉验证,三个哈希值全部正确。

完整代码

use digest::Digest;
use hex;
use md5::Md5;
use sha1::Sha1;
use sha2::Sha256;
use std::fs;
use std::io::{self, Write};

struct HashResult {
    md5: String,
    sha1: String,
    sha256: String,
}

fn compute_hashes(data: &[u8]) -> HashResult {
    HashResult {
        md5: hex::encode(Md5::digest(data)),
        sha1: hex::encode(Sha1::digest(data)),
        sha256: hex::encode(Sha256::digest(data)),
    }
}

fn run() -> io::Result<()> {
    let args: Vec<String> = std::env::args().collect();
    if args.len() < 2 {
        eprintln!("用法: {} <文件路径>", args[0]);
        std::process::exit(1);
    }

    let path = &args[1];
    let data = fs::read(path).map_err(|e| {
        let _ = writeln!(io::stderr(), "读取文件失败: {} - {}", path, e);
        e
    })?;

    let result = compute_hashes(&data);

    println!("文件: {}", path);
    println!("{:-<50}", "");
    println!("{:<10} {}", "MD5:",     result.md5);
    println!("{:<10} {}", "SHA1:",    result.sha1);
    println!("{:<10} {}", "SHA256:",  result.sha256);

    Ok(())
}

fn main() {
    if let Err(e) = run() {
        let _ = writeln!(io::stderr(), "错误: {}", e);
        std::process::exit(1);
    }
}

小结

从零到完整可运行,全程没有手写一行 Rust 代码,只在用中文描述需求。OpenCode 负责了项目初始化、依赖管理、代码生成、错误处理优化、编译调试的全流程。

对比传统开发方式:查 crate 文档 → 写代码 → 调编译错误 → 改代码,怎么也得一刻钟。现在 4 分钟搞定,效率提升明显。尤其是修正错误时——直接告诉它"这样不对,换成 anyhow",它马上重构,不需要自己去翻文档。