Skip to content

Commit 3f79bdc

Browse files
authored
Rollup merge of #41125 - lukaramu:std-hash-docs, r=frewsxcv
Improve std::hash docs Fixes #29357. For details on what exactly I've done, see the commit descriptions. There are some things I'm not sure about, but would like to address before merging this so the issue can be closed; any feedback on these points would really be appriciated: * [x] ~I didn't touch the module level docs at all. On the one hand, I think they could use a short overview over the module; on the other hand, the module really isn't that big and I don't know if I could really do anything beyond just duplicating the type's summaries...~ * [x] ~I feel like the module-level examples are quite long-winded and not to the point, but I couldn't really think of anything better. Any ideas?~ * [x] ~Should `Hasher` get an example for implementing it? There is one in the module documentation, but it only "implements" it via `unimplemented!` and I'm not sure what the value of that is.~ * [x] ~Should `Hasher`'s `write_{int}` methods get examples?~ If there's anything else you'd like to see in std::hash's docs, please let me know! r? @rust-lang/docs
2 parents f0ca5d4 + 12d7c3d commit 3f79bdc

File tree

1 file changed

+164
-33
lines changed

1 file changed

+164
-33
lines changed

src/libcore/hash/mod.rs

+164-33
Original file line numberDiff line numberDiff line change
@@ -107,29 +107,25 @@ mod sip;
107107

108108
/// A hashable type.
109109
///
110-
/// The `H` type parameter is an abstract hash state that is used by the `Hash`
111-
/// to compute the hash.
110+
/// Types implementing `Hash` are able to be [`hash`]ed with an instance of
111+
/// [`Hasher`].
112112
///
113-
/// If you are also implementing [`Eq`], there is an additional property that
114-
/// is important:
113+
/// ## Implementing `Hash`
115114
///
116-
/// ```text
117-
/// k1 == k2 -> hash(k1) == hash(k2)
118-
/// ```
119-
///
120-
/// In other words, if two keys are equal, their hashes should also be equal.
121-
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
115+
/// You can derive `Hash` with `#[derive(Hash)]` if all fields implement `Hash`.
116+
/// The resulting hash will be the combination of the values from calling
117+
/// [`hash`] on each field.
122118
///
123-
/// ## Derivable
124-
///
125-
/// This trait can be used with `#[derive]` if all fields implement `Hash`.
126-
/// When `derive`d, the resulting hash will be the combination of the values
127-
/// from calling [`.hash`] on each field.
128-
///
129-
/// ## How can I implement `Hash`?
119+
/// ```
120+
/// #[derive(Hash)]
121+
/// struct Rustacean {
122+
/// name: String,
123+
/// country: String,
124+
/// }
125+
/// ```
130126
///
131-
/// If you need more control over how a value is hashed, you need to implement
132-
/// the `Hash` trait:
127+
/// If you need more control over how a value is hashed, you can of course
128+
/// implement the `Hash` trait yourself:
133129
///
134130
/// ```
135131
/// use std::hash::{Hash, Hasher};
@@ -148,17 +144,60 @@ mod sip;
148144
/// }
149145
/// ```
150146
///
147+
/// ## `Hash` and `Eq`
148+
///
149+
/// When implementing both `Hash` and [`Eq`], it is important that the following
150+
/// property holds:
151+
///
152+
/// ```text
153+
/// k1 == k2 -> hash(k1) == hash(k2)
154+
/// ```
155+
///
156+
/// In other words, if two keys are equal, their hashes must also be equal.
157+
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
158+
///
159+
/// Thankfully, you won't need to worry about upholding this property when
160+
/// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`.
161+
///
151162
/// [`Eq`]: ../../std/cmp/trait.Eq.html
163+
/// [`Hasher`]: trait.Hasher.html
152164
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
153165
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
154-
/// [`.hash`]: #tymethod.hash
166+
/// [`hash`]: #tymethod.hash
155167
#[stable(feature = "rust1", since = "1.0.0")]
156168
pub trait Hash {
157-
/// Feeds this value into the state given, updating the hasher as necessary.
169+
/// Feeds this value into the given [`Hasher`].
170+
///
171+
/// # Examples
172+
///
173+
/// ```
174+
/// use std::collections::hash_map::DefaultHasher;
175+
/// use std::hash::{Hash, Hasher};
176+
///
177+
/// let mut hasher = DefaultHasher::new();
178+
/// 7920.hash(&mut hasher);
179+
/// println!("Hash is {:x}!", hasher.finish());
180+
/// ```
181+
///
182+
/// [`Hasher`]: trait.Hasher.html
158183
#[stable(feature = "rust1", since = "1.0.0")]
159184
fn hash<H: Hasher>(&self, state: &mut H);
160185

161-
/// Feeds a slice of this type into the state provided.
186+
/// Feeds a slice of this type into the given [`Hasher`].
187+
///
188+
/// # Examples
189+
///
190+
/// ```
191+
/// use std::collections::hash_map::DefaultHasher;
192+
/// use std::hash::{Hash, Hasher};
193+
///
194+
/// let mut hasher = DefaultHasher::new();
195+
/// let numbers = [6, 28, 496, 8128];
196+
/// Hash::hash_slice(&numbers, &mut hasher);
197+
/// println!("Hash is {:x}!", hasher.finish());
198+
/// ```
199+
///
200+
/// [`Hasher`]: trait.Hasher.html
162201
#[stable(feature = "hash_slice", since = "1.3.0")]
163202
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
164203
where Self: Sized
@@ -169,18 +208,73 @@ pub trait Hash {
169208
}
170209
}
171210

172-
/// A trait which represents the ability to hash an arbitrary stream of bytes.
211+
/// A trait for hashing an arbitrary stream of bytes.
212+
///
213+
/// Instances of `Hasher` usually represent state that is changed while hashing
214+
/// data.
215+
///
216+
/// `Hasher` provides a fairly basic interface for retrieving the generated hash
217+
/// (with [`finish`]), and writing integers as well as slices of bytes into an
218+
/// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher`
219+
/// instances are used in conjunction with the [`Hash`] trait.
220+
///
221+
/// # Examples
222+
///
223+
/// ```
224+
/// use std::collections::hash_map::DefaultHasher;
225+
/// use std::hash::Hasher;
226+
///
227+
/// let mut hasher = DefaultHasher::new();
228+
///
229+
/// hasher.write_u32(1989);
230+
/// hasher.write_u8(11);
231+
/// hasher.write_u8(9);
232+
/// hasher.write(b"Huh?");
233+
///
234+
/// println!("Hash is {:x}!", hasher.finish());
235+
/// ```
236+
///
237+
/// [`Hash`]: trait.Hash.html
238+
/// [`finish`]: #tymethod.finish
239+
/// [`write`]: #tymethod.write
240+
/// [`write_u8`]: #method.write_u8
173241
#[stable(feature = "rust1", since = "1.0.0")]
174242
pub trait Hasher {
175243
/// Completes a round of hashing, producing the output hash generated.
244+
///
245+
/// # Examples
246+
///
247+
/// ```
248+
/// use std::collections::hash_map::DefaultHasher;
249+
/// use std::hash::Hasher;
250+
///
251+
/// let mut hasher = DefaultHasher::new();
252+
/// hasher.write(b"Cool!");
253+
///
254+
/// println!("Hash is {:x}!", hasher.finish());
255+
/// ```
176256
#[stable(feature = "rust1", since = "1.0.0")]
177257
fn finish(&self) -> u64;
178258

179259
/// Writes some data into this `Hasher`.
260+
///
261+
/// # Examples
262+
///
263+
/// ```
264+
/// use std::collections::hash_map::DefaultHasher;
265+
/// use std::hash::Hasher;
266+
///
267+
/// let mut hasher = DefaultHasher::new();
268+
/// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
269+
///
270+
/// hasher.write(&data);
271+
///
272+
/// println!("Hash is {:x}!", hasher.finish());
273+
/// ```
180274
#[stable(feature = "rust1", since = "1.0.0")]
181275
fn write(&mut self, bytes: &[u8]);
182276

183-
/// Write a single `u8` into this hasher.
277+
/// Writes a single `u8` into this hasher.
184278
#[inline]
185279
#[stable(feature = "hasher_write", since = "1.3.0")]
186280
fn write_u8(&mut self, i: u8) {
@@ -258,12 +352,35 @@ pub trait Hasher {
258352
}
259353
}
260354

261-
/// A `BuildHasher` is typically used as a factory for instances of `Hasher`
262-
/// which a `HashMap` can then use to hash keys independently.
355+
/// A trait for creating instances of [`Hasher`].
356+
///
357+
/// A `BuildHasher` is typically used (e.g. by [`HashMap`]) to create
358+
/// [`Hasher`]s for each key such that they are hashed independently of one
359+
/// another, since [`Hasher`]s contain state.
360+
///
361+
/// For each instance of `BuildHasher`, the [`Hasher`]s created by
362+
/// [`build_hasher`] should be identical. That is, if the same stream of bytes
363+
/// is fed into each hasher, the same output will also be generated.
364+
///
365+
/// # Examples
366+
///
367+
/// ```
368+
/// use std::collections::hash_map::RandomState;
369+
/// use std::hash::{BuildHasher, Hasher};
370+
///
371+
/// let s = RandomState::new();
372+
/// let mut hasher_1 = s.build_hasher();
373+
/// let mut hasher_2 = s.build_hasher();
263374
///
264-
/// Note that for each instance of `BuildHasher`, the created hashers should be
265-
/// identical. That is, if the same stream of bytes is fed into each hasher, the
266-
/// same output will also be generated.
375+
/// hasher_1.write_u32(8128);
376+
/// hasher_2.write_u32(8128);
377+
///
378+
/// assert_eq!(hasher_1.finish(), hasher_2.finish());
379+
/// ```
380+
///
381+
/// [`build_hasher`]: #tymethod.build_hasher
382+
/// [`Hasher`]: trait.Hasher.html
383+
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
267384
#[stable(since = "1.7.0", feature = "build_hasher")]
268385
pub trait BuildHasher {
269386
/// Type of the hasher that will be created.
@@ -272,6 +389,9 @@ pub trait BuildHasher {
272389

273390
/// Creates a new hasher.
274391
///
392+
/// Each call to `build_hasher` on the same instance should produce identical
393+
/// [`Hasher`]s.
394+
///
275395
/// # Examples
276396
///
277397
/// ```
@@ -281,15 +401,23 @@ pub trait BuildHasher {
281401
/// let s = RandomState::new();
282402
/// let new_s = s.build_hasher();
283403
/// ```
404+
///
405+
/// [`Hasher`]: trait.Hasher.html
284406
#[stable(since = "1.7.0", feature = "build_hasher")]
285407
fn build_hasher(&self) -> Self::Hasher;
286408
}
287409

288-
/// The `BuildHasherDefault` structure is used in scenarios where one has a
289-
/// type that implements [`Hasher`] and [`Default`], but needs that type to
290-
/// implement [`BuildHasher`].
410+
/// Used to create a default [`BuildHasher`] instance for types that implement
411+
/// [`Hasher`] and [`Default`].
291412
///
292-
/// This structure is zero-sized and does not need construction.
413+
/// `BuildHasherDefault<H>` can be used when a type `H` implements [`Hasher`] and
414+
/// [`Default`], and you need a corresponding [`BuildHasher`] instance, but none is
415+
/// defined.
416+
///
417+
/// Any `BuildHasherDefault` is [zero-sized]. It can be created with
418+
/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or
419+
/// [`HashSet`], this doesn't need to be done, since they implement appropriate
420+
/// [`Default`] instances themselves.
293421
///
294422
/// # Examples
295423
///
@@ -322,8 +450,11 @@ pub trait BuildHasher {
322450
///
323451
/// [`BuildHasher`]: trait.BuildHasher.html
324452
/// [`Default`]: ../default/trait.Default.html
453+
/// [method.default]: #method.default
325454
/// [`Hasher`]: trait.Hasher.html
326455
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
456+
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
457+
/// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts
327458
#[stable(since = "1.7.0", feature = "build_hasher")]
328459
pub struct BuildHasherDefault<H>(marker::PhantomData<H>);
329460

0 commit comments

Comments
 (0)