pub trait Hasher {
Show 16 methods
// Required methods
fn finish(&self) -> u64;
fn write(&mut self, bytes: &[u8]);
// Provided methods
fn write_u8(&mut self, i: u8) { ... }
fn write_u16(&mut self, i: u16) { ... }
fn write_u32(&mut self, i: u32) { ... }
fn write_u64(&mut self, i: u64) { ... }
fn write_u128(&mut self, i: u128) { ... }
fn write_usize(&mut self, i: usize) { ... }
fn write_i8(&mut self, i: i8) { ... }
fn write_i16(&mut self, i: i16) { ... }
fn write_i32(&mut self, i: i32) { ... }
fn write_i64(&mut self, i: i64) { ... }
fn write_i128(&mut self, i: i128) { ... }
fn write_isize(&mut self, i: isize) { ... }
fn write_length_prefix(&mut self, len: usize) { ... }
fn write_str(&mut self, s: &str) { ... }
}
Expand description
对任意字节流进行散列的 trait。
Hasher
的实例通常表示在对数据进行哈希处理时更改的状态。
Hasher
提供了一个相当基本的接口,用于检索生成的散列 (使用 finish
),并将整数和字节片写入实例 (使用 write
和 write_u8
等)。
大多数情况下,Hasher
实例与 Hash
trait 结合使用。
这个 trait 不保证如何定义各种 write_*
方法,并且 Hash
的实现不应假设它们以一种或另一种方式工作。
例如,您不能假设一个 write_u32
调用等同于 write_u8
的四个调用。
您也不能假设相邻的 write
调用是合并的,所以有可能,例如,
hasher.write(&[1, 2]);
hasher.write(&[3, 4, 5, 6]);
Runand
hasher.write(&[1, 2, 3, 4]);
hasher.write(&[5, 6]);
Run最终产生不同的哈希值。
因此,为了产生相同的散列值,Hash
实现必须确保对等价项进行完全相同的调用序列 – 相同的方法具有相同的参数以相同的顺序。
Examples
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
hasher.write_u32(1989);
hasher.write_u8(11);
hasher.write_u8(9);
hasher.write(b"Huh?");
println!("Hash is {:x}!", hasher.finish());
RunRequired Methods§
sourcefn write(&mut self, bytes: &[u8])
fn write(&mut self, bytes: &[u8])
将一些数据写入此 Hasher
。
Examples
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DefaultHasher::new();
let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
hasher.write(&data);
println!("Hash is {:x}!", hasher.finish());
Run给实现者的注意事项
您通常不应该将长度前缀作为实现此方法的一部分。
在需要它的序列之前调用 Hasher::write_length_prefix
取决于 Hash
实现。
Provided Methods§
1.26.0 · sourcefn write_u128(&mut self, i: u128)
fn write_u128(&mut self, i: u128)
将单个 u128
写入此哈希器。
1.3.0 · sourcefn write_usize(&mut self, i: usize)
fn write_usize(&mut self, i: usize)
将单个 usize
写入此哈希器。
1.26.0 · sourcefn write_i128(&mut self, i: i128)
fn write_i128(&mut self, i: i128)
将单个 i128
写入此哈希器。
1.3.0 · sourcefn write_isize(&mut self, i: isize)
fn write_isize(&mut self, i: isize)
将单个 isize
写入此哈希器。
sourcefn write_length_prefix(&mut self, len: usize)
fn write_length_prefix(&mut self, len: usize)
hasher_prefixfree_extras
#96762)将长度前缀写入此哈希器,作为无前缀的一部分。
如果您正在为自定义集合实现 Hash
,请在将其内容写入此 Hasher
之前调用 this。
这样 (collection![1, 2, 3], collection![4, 5])
和 (collection![1, 2], collection![3, 4, 5])
将为 Hasher
提供不同的值序列
impl<T> Hash for [T]
包含对该方法的调用,因此如果您通过其 Hash::hash
方法对切片 (或数组或 vector) 进行哈希处理,您不应该 ** 自己调用 this。
此方法仅用于提供域分离。
如果您想对表示 data 的一部分的 usize
进行散列处理,那么将其传递给 Hasher::write_usize
而不是此方法很重要。
Examples
#![feature(hasher_prefixfree_extras)]
use std::hash::{Hash, Hasher};
impl<T: Hash> Hash for MyCollection<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_length_prefix(self.len());
for elt in self {
elt.hash(state);
}
}
}
Run给实现者的注意事项
如果您确定您的 Hasher
愿意受到 Hash-DoS 攻击,那么您可以考虑跳过以提高性能为名提供的部分或全部 len
的散列。
sourcefn write_str(&mut self, s: &str)
fn write_str(&mut self, s: &str)
hasher_prefixfree_extras
#96762)将单个 str
写入此哈希器。
如果您正在实现 Hash
,您通常不需要像 impl Hash for str
那样调用 this,所以您应该更喜欢它。
这包括前缀自由的域分隔符,所以在调用它之前您不应该 ** 调用 Self::write_length_prefix
。
给实现者的注意事项
至少有两种合理的默认方式来实现这一点。 哪一个将是默认值尚未确定,所以现在您可能想要专门覆盖它。
一般答案
使用长度前缀来实现它总是正确的:
fn write_str(&mut self, s: &str) {
self.write_length_prefix(s.len());
self.write(s.as_bytes());
}
Run而且,如果您的 Hasher
在 usize
块中工作,这可能是一种非常有效的方法,因为任何更复杂的事情最终都可能比仅以长度运行一轮更慢。
如果您的 Hasher
按字节工作
str
是 UTF-8 的一个好处是 b'\xFF'
字节永远不会发生。这意味着您可以将其,追加,到被散列的字节流并保持前缀自由:
fn write_str(&mut self, s: &str) {
self.write(s.as_bytes());
self.write_u8(0xff);
}
Run这确实要求您的实现不添加额外的填充,因此通常需要您维护一个缓冲区,仅在该缓冲区已满 (或调用 finish
) 时运行一轮。
那是因为如果 write
将数据填充到固定的块大小,它很可能会以这样的方式进行,即 "a"
和 "a\x00"
最终会散列相同的事物序列,从而引入冲突。