泛型函数,用于计算哈希(digest :: Digest trait)并获取String [英] Generic function to compute a hash (digest::Digest trait) and get back a String
问题描述
在解决这个问题时我有些头疼.我正在尝试编写一个通用函数,该函数可以采用任何 digest :: Digest
并吐出所计算摘要的字符串形式(十六进制字符串").
I have a little bit of trouble wrapping my head around this problem. I am trying to write a generic function which can take any digest::Digest
and spits out a string form of the computed digest ("hex string").
这是非通用版本作为最小示例:
#![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);
}
... and here is my attempt 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);
}
...会出现以下错误:
... which gives the following error:
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
的实现出现了需要 GenericArray< u8,N>
的 OutputSize
的 std :: ops :: Add
(即 N
),由 .finalize()
返回.但是,非通用示例表明 ArrayLength< u8>
有这样的实现.
Now suppose I understand the error correctly, the implementation of std::fmt::LowerHex
used by format!()
appears to require std::ops::Add
for the OutputSize
of the GenericArray<u8, N>
(i.e. the N
) which is returned by .finalize()
. However, the non-generic example suggests that there is such an implementation for ArrayLength<u8>
.
因此,考虑到我无法为外部类型实现 std :: ops :: Add
特征,在这种情况下如何满足编译器要求?
So, given I cannot implement the std::ops::Add
trait for an external type, how can I satisfy the compiler in this case?
或者也许可以改一下我的问题,尽管我-Rust的新手-不能100%地确定我想要的是什么:我如何告诉编译器将< D视为sha2 :: Digest> ;?:: OutputSize
与 ArrayLength< u8>
吗?
Or maybe to rephrase my question, although I - being new with Rust - am not a 100% sure it is what I want: how do I tell the compiler to treat <D as sha2::Digest>::OutputSize
the same as ArrayLength<u8>
?
注意::我对Rust还是比较陌生,因此请记住这一点,请参阅适用于我的案例的 exact 文档,而不是该文档"一般来说.我已经搜索了 digest
的文档,各种 digest :: Digest
的实现者,该错误以及(我认为是)类似问题和特质主题的文档.在我问之前,在Rust Book(2018版)中阅读了将近三个小时.谢谢.
NB: I am relatively new with Rust, so please keep that in mind and kindly refer to the exact piece of documentation applicable to my case, rather than "the documentation" in general. I have scoured the documentation for digest
, for various of the implementers of digest::Digest
, for this error and for (what I thought were) similar issues and the traits topics in the Rust Book (2018 edition) for nearly three hours before I asked. Thanks.
在第二个示例中,我使用 use摘要::摘要;
.那是因为将来应该采用其他哈希算法,直接使用 digest :: Digest
而不是从其中一种重新导出的 Digest
似乎更有意义实施者.如果有反对的理由,请随时在上面评论.
In the second example I am using use digest::Digest;
. That's because in the future other hash algorithms are supposed to follow and it seemed to make more sense to use digest::Digest
directly instead of the re-exported Digest
from one of the implementers. If there is a reason against that, feel free to remark on it.
推荐答案
Rust要求您指定泛型中使用的所有功能.注意:
Rust requires that you specify all the functionality you use in generics. The note:
| ^^^^^^ 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`
试图说我们正在对类型 D :: OutputSize
使用 Add
,但不要求将其作为约束,我们可以这样做:>
is trying to say that we are using Add
on the type D::OutputSize
but not requiring it as a constraint, which we can do like so:
fn compute_hash<D: Digest>(input_data: &str) -> String
where D::OutputSize: std::ops::Add
如果进行此更改,则会出现下一个错误:
If you make this change, you'll come to the next error:
| ^^^^^^ the trait `digest::generic_array::ArrayLength<u8>` is not implemented for `<<D as sha2::Digest>::OutputSize as std::ops::Add>::Output`
所以还有另一个要求,但是我们也可以添加它:
so there is another requirement, but we can add that too:
fn compute_hash<D: Digest>(input_data: &str) -> String
where D::OutputSize: std::ops::Add,
<D::OutputSize as std::ops::Add>::Output: digest::generic_array::ArrayLength<u8>
这将编译.
但是让我们深入探讨为什么需要这些约束的原因. 完成
返回 Output< D>
,我们知道它是需要特征 LowerHex
,因此我们可以看到此类型何时满足此特征.请参见:
But let's dive into the reasons why these constraints are necessary. finalize
returns Output<D>
and we know that it is the type GenericArray<u8, <D as Digest>::OutputSize>
. Evidently format!("{:x}", ...)
requires the trait LowerHex
so we can see when this type satisfies this trait. See:
impl<T: ArrayLength<u8>> LowerHex for GenericArray<u8, T>
where
T: Add<T>,
<T as Add<T>>::Output: ArrayLength<u8>,
那看起来很熟悉.因此,如果这些约束为true,则 finalize
的返回类型满足 LowerHex
.
That looks familiar. So the return type of finalize
is satisfies LowerHex
if these constraints are true.
但是我们可以更直接地得到同一件事.我们希望能够使用 LowerHex
和
But we can get at the same thing more directly. We want to be able to format using LowerHex
and we can say that:
fn compute_hash<D: Digest>(input_data: &str) -> String
where digest::Output<D>: core::fmt::LowerHex
因为这可以直接表达我们在泛型函数中使用的内容,所以这似乎是可取的.
Since this can directly express what we use in the generic function, this seems preferable.
这篇关于泛型函数,用于计算哈希(digest :: Digest trait)并获取String的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!