泛型函数,用于计算哈希(digest :: Digest trait)并获取String [英] Generic function to compute a hash (digest::Digest trait) and get back a String

查看:52
本文介绍了泛型函数,用于计算哈希(digest :: Digest trait)并获取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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆