【发布时间】:2020-10-13 20:06:05
【问题描述】:
我在解决这个问题时遇到了一些麻烦。我正在尝试编写一个通用函数,它可以采用任何digest::Digest 并吐出计算摘要的字符串形式(“十六进制字符串”)。
这里是the non-generic version 作为最小示例:
#![forbid(unsafe_code)]
#![forbid(warnings)]
extern crate sha2; // 0.9.1
use sha2::{Sha256, Digest}; // 0.9.1
fn main() {
let hash = Sha256::new().chain("String data").finalize();
let s = format!("{:x}", hash);
println!("Result: {}", s);
}
...这是我的尝试at a generic version:
#![forbid(unsafe_code)]
#![forbid(warnings)]
extern crate sha2; // 0.9.1
extern crate digest; // 0.9.0
use digest::Digest;
use sha2::Sha256;
fn compute_hash<D: Digest>(input_data: &str) -> String {
let mut hasher = D::new();
hasher.update(input_data.as_bytes());
let digest = hasher.finalize();
format!("{:x}", digest)
}
fn main() {
let s = compute_hash::<Sha256>("String data");
println!("Result: {}", s);
}
... 这给出了以下错误:
Compiling playground v0.0.1 (/playground)
error[E0277]: cannot add `<D as sha2::Digest>::OutputSize` to `<D as sha2::Digest>::OutputSize`
--> src/lib.rs:13:21
|
13 | format!("{:x}", digest)
| ^^^^^^ no implementation for `<D as sha2::Digest>::OutputSize + <D as sha2::Digest>::OutputSize`
|
= help: the trait `std::ops::Add` is not implemented for `<D as sha2::Digest>::OutputSize`
= note: required because of the requirements on the impl of `std::fmt::LowerHex` for `digest::generic_array::GenericArray<u8, <D as sha2::Digest>::OutputSize>`
= note: required by `std::fmt::LowerHex::fmt`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting the associated type
|
9 | fn compute_hash<D: Digest>(input_data: &str) -> String where <D as sha2::Digest>::OutputSize: std::ops::Add {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`.
现在假设我正确理解了错误,format!() 使用的std::fmt::LowerHex 的实现似乎需要std::ops::Add 用于GenericArray<u8, N> 的OutputSize(即@987654333 @) 由.finalize() 返回。但是,非通用示例表明ArrayLength<u8> 存在这样的实现。
所以,鉴于我无法为外部类型实现 std::ops::Add 特征,在这种情况下如何满足编译器的要求?
或者改写我的问题,虽然我 - 刚接触 Rust - 并不是 100% 确定这是我想要的:我如何告诉编译器将 <D as sha2::Digest>::OutputSize 与 ArrayLength<u8> 一样对待?
注意:我对 Rust 比较陌生,所以请记住这一点,并请参考适用于我的案例的确切文档,而不是“文件”一般。近三个小时前,我已经搜索了 digest 的文档、digest::Digest 的各种实现者、这个错误以及(我认为是)类似问题和 Rust Book(2018 版)中的特征主题我问。谢谢。
在第二个示例中,我使用use digest::Digest;。那是因为将来应该遵循其他哈希算法,并且直接使用digest::Digest 而不是从其中一位实现者重新导出的Digest 似乎更有意义。如果有反对的理由,请随时发表评论。
【问题讨论】:
-
可能值得注意的是
digestcrate 使用generic_array来解决const generics 缺乏语言支持的问题。该语言的未来版本似乎可能允许digest以更直接的方式支持这种用法。