如何创建基于match或enum自动匹配填充对应hash类型的Rust函数
Rust根据flag参数动态选择哈希算法实现方案
你定义的create_hash是泛型函数,泛型参数为编译期静态分发,无法直接将运行时传入的flag变量映射为编译期类型,可通过以下两种方案实现需求:
方案1:调用处直接匹配flag(无额外封装,实现最简单)
直接在generate_string_hash函数中对flag做分支匹配,每个分支传入对应哈希算法的实例即可,原有create_hash函数无需修改:
// 提前引入依赖的哈希算法 use sha1::Sha1; use sha2::{Sha256, Sha512}; use libc::{c_char, i32}; use std::ffi::{CStr, CString}; // 提前约定flag取值对应哈希类型: // 0 -> SHA1 // 1 -> SHA256 // 2 -> SHA512 #[no_mangle] pub extern "C" fn generate_string_hash(hashptr: *mut c_char, flag: u8, result_ptr: *mut i32) { unsafe { if SW == 0 { return(); } } let chash: &CStr = unsafe { CStr::from_ptr(hashptr) }; let msg = chash.to_str().expect("输入字符串不是合法UTF-8格式"); // 运行时匹配flag生成对应哈希实例 let hash_res = match flag { 0 => cryptography::create_hash(msg, Sha1::default()), 1 => cryptography::create_hash(msg, Sha256::default()), 2 => cryptography::create_hash(msg, Sha512::default()), _ => panic!("不支持的哈希类型flag:{}", flag) // 生产环境建议替换为返回错误码 }; unsafe { *result_ptr = CString::new(hash_res).unwrap().into_raw() as i32; } } // 原有create_hash无需修改 fn create_hash<D>(msg: &str, mut hasher: D) -> String where D: Digest, digest::Output<D>: std::fmt::LowerHex, { hasher.update(msg); format!("{:x}", hasher.finalize()) }
方案2:枚举包装哈希算法统一接口(适合哈希类型多、需要复用的场景)
如果支持的哈希类型很多,或者需要多处调用create_hash,可以用枚举封装所有支持的哈希算法,为枚举实现Digest特征后即可统一传参:
// 定义枚举包装所有支持的哈希算法 enum HasherSelector { Sha1(Sha1), Sha256(Sha256), Sha512(Sha512), } // 为枚举实现Digest特征,方法全部转发到内部的实际哈希实例 impl Digest for HasherSelector { type Output = String; fn update(&mut self, data: &[u8]) { match self { HasherSelector::Sha1(h) => h.update(data), HasherSelector::Sha256(h) => h.update(data), HasherSelector::Sha512(h) => h.update(data), } } fn finalize(self) -> Self::Output { match self { HasherSelector::Sha1(h) => format!("{:x}", h.finalize()), HasherSelector::Sha256(h) => format!("{:x}", h.finalize()), HasherSelector::Sha512(h) => format!("{:x}", h.finalize()), } } fn finalize_reset(&mut self) -> Self::Output { match self { HasherSelector::Sha1(h) => format!("{:x}", h.finalize_reset()), HasherSelector::Sha256(h) => format!("{:x}", h.finalize_reset()), HasherSelector::Sha512(h) => format!("{:x}", h.finalize_reset()), } } fn reset(&mut self) { match self { HasherSelector::Sha1(h) => h.reset(), HasherSelector::Sha256(h) => h.reset(), HasherSelector::Sha512(h) => h.reset(), } } fn output_size() -> usize { 64 } }
封装后generate_string_hash的调用逻辑可简化为:
let hasher = match flag { 0 => HasherSelector::Sha1(Sha1::default()), 1 => HasherSelector::Sha256(Sha256::default()), 2 => HasherSelector::Sha512(Sha512::default()), _ => panic!("不支持的哈希类型flag:{}", flag) }; let hash_res = cryptography::create_hash(msg, hasher);
注意事项
- 你原有代码中调用
create_hash时多传入了flag参数,和函数定义的入参数量不符,属于笔误需要删除 - 你通过
into_raw()返回的C字符串是Rust堆分配的内存,C端使用完后必须调用Rust侧导出的释放函数回收,否则会出现内存泄漏 - 非法flag的分支建议替换为返回错误码写入
result_ptr,不要直接panic,避免C端程序直接崩溃
内容的提问来源于stack exchange,提问作者silak
相关产品推荐
相关产品推荐

