Rust中循环更新HashMap内DynDigest实例的正确方法
HashMap中哈希器未正确更新的问题解决
问题现象
存储了实现digest::DynDigest的不同哈希算法的HashMap,在循环调用update()后,所有哈希值始终相同(均为Sha224的空输入哈希d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f),即使修改目标文件路径,结果也无变化。
问题根源
代码中多次使用hashers.to_owned(),该方法会创建整个HashMap的完整副本,包括每个哈希器的克隆实例。循环中更新的是这些临时副本,原HashMap中的哈希器始终处于初始状态;最终调用finalize()时,操作的还是未被修改的原哈希器,因此得到的都是空输入的哈希值。
修正方案
关键修改点
- 将函数参数改为可变引用,避免所有权转移,允许直接修改原哈希器实例
- 遍历哈希器时使用可变引用,而非克隆整个HashMap
- 处理
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
相关产品推荐
相关产品推荐

