You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中循环更新HashMap内DynDigest实例的正确方法

HashMap中哈希器未正确更新的问题解决

问题现象

存储了实现digest::DynDigest的不同哈希算法的HashMap,在循环调用update()后,所有哈希值始终相同(均为Sha224的空输入哈希d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f),即使修改目标文件路径,结果也无变化。

问题根源

代码中多次使用hashers.to_owned(),该方法会创建整个HashMap的完整副本,包括每个哈希器的克隆实例。循环中更新的是这些临时副本,原HashMap中的哈希器始终处于初始状态;最终调用finalize()时,操作的还是未被修改的原哈希器,因此得到的都是空输入的哈希值。

修正方案

关键修改点

  1. 将函数参数改为可变引用,避免所有权转移,允许直接修改原哈希器实例
  2. 遍历哈希器时使用可变引用,而非克隆整个HashMap
  3. 处理finalize()消耗哈希器的特性:可通过克隆哈希器生成结果,或直接消耗原实例

修正后的代码

use digest::{Digest, DynDigest};
use sha2;
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::{BufReader, Read};
use std::path::PathBuf;

fn checksum_to_hex(bytes: &[u8]) -> String {
    bytes.iter().map(|b| format!("{:02x}", b)).collect()
}

pub fn hash_file(
    fpath: PathBuf,
    hashers: &mut HashMap<&str, Box<dyn DynDigest>>,
) -> io::Result<HashMap<&str, String>> {
    let f = File::open(fpath)?;
    let mut buffer = [0u8; 1048576];
    let mut reader = BufReader::new(f);

    loop {
        let count = reader.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        // 遍历可变引用,直接更新原哈希器状态
        for (_, hasher) in hashers.iter_mut() {
            hasher.update(&buffer[..count]);
        }
    }

    let mut hashes: HashMap<&str, String> = HashMap::new();
    // 克隆哈希器以生成结果,保留原实例可后续复用
    for (k, hasher) in hashers.iter() {
        let mut cloned_hasher = hasher.clone_box();
        let res = checksum_to_hex(cloned_hasher.finalize().as_slice());
        hashes.insert(k, res);
    }

    Ok(hashes)
}

fn main() {
    let mut hashers: HashMap<&str, Box<dyn DynDigest>> = HashMap::new();

    hashers.insert("Sha224", Box::new(sha2::Sha224::new()));
    hashers.insert("Sha256", Box::new(sha2::Sha256::new()));
    hashers.insert("Sha512", Box::new(sha2::Sha512::new()));

    let results = hash_file(PathBuf::from("/bin/ls"), &mut hashers).expect("哈希计算失败");
    for (htype, hashres) in results {
        println!("  {} {}", htype, hashres);
    }
}

可选优化(不保留原哈希器)

如果不需要保留原哈希器实例,可以直接消耗它们生成结果,省略克隆步骤:

// 替换结果生成部分的代码
for (k, hasher) in hashers.drain() {
    let res = checksum_to_hex(hasher.finalize().as_slice());
    hashes.insert(k, res);
}

内容的提问来源于stack exchange,提问作者raspi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 19:15:52