|
14 | 14 |
|
15 | 15 | /// A trait identifying how borrowed data behaves.
|
16 | 16 | ///
|
17 |
| -/// If a type implements this trait, it signals that a reference to it behaves |
18 |
| -/// exactly like a reference to `Borrowed`. As a consequence, if a trait is |
19 |
| -/// implemented both by `Self` and `Borrowed`, all trait methods that |
20 |
| -/// take a `&self` argument must produce the same result in both |
21 |
| -/// implementations. |
22 |
| -/// |
23 |
| -/// As a consequence, this trait should only be implemented for types managing |
24 |
| -/// a value of another type without modifying its behavior. Examples are |
25 |
| -/// smart pointers such as [`Box<T>`] or [`Rc<T>`] as well the owned version |
26 |
| -/// of slices such as [`Vec<T>`]. |
27 |
| -/// |
28 |
| -/// A relaxed version that allows converting a reference to some other type |
29 |
| -/// without any further promises is available through [`AsRef`]. |
| 17 | +/// In Rust, it is common to provide different representations of a type for |
| 18 | +/// different use cases. For instance, storage location and management for a |
| 19 | +/// value can be specifically chosen as appropriate for a particular use via |
| 20 | +/// pointer types such as [`Box<T>`] or [`Rc<T>`] or one can opt into |
| 21 | +/// concurrency via synchronization types such as [`Mutex<T>`], avoiding the |
| 22 | +/// associated cost when in parallel doesn’t happen. Beyond these generic |
| 23 | +/// wrappers that can be used with any type, some types provide optional |
| 24 | +/// facets providing potentially costly functionality. An example for such a |
| 25 | +/// type is [`String`] which adds the ability to extend a string to the basic |
| 26 | +/// [`str`]. This requires keeping additional information unnecessary for a |
| 27 | +/// simple, imutable string. |
| 28 | +/// |
| 29 | +/// These types signal that they are a specialized representation of a basic |
| 30 | +/// type `T` by implementing `Borrow<T>`. The method `borrow` provides a way |
| 31 | +/// to convert a reference to the type into a reference to the underlying |
| 32 | +/// basic type. |
| 33 | +/// |
| 34 | +/// If a type implementing `Borrow<T>` implements other traits also |
| 35 | +/// implemented by `T`, these implementations behave identically if the trait |
| 36 | +/// is concerned with the data rather than its representation. For instance, |
| 37 | +/// the comparison traits such as `PartialEq` or `PartialOrd` must behave |
| 38 | +/// identical for `T` and any type implemeting `Borrow<T>`. |
30 | 39 | ///
|
31 | 40 | /// When writing generic code, a use of `Borrow` should always be justified
|
32 | 41 | /// by additional trait bounds, making it clear that the two types need to
|
|
37 | 46 | /// The companion trait [`BorrowMut`] provides the same guarantees for
|
38 | 47 | /// mutable references.
|
39 | 48 | ///
|
40 |
| -/// [`Box<T>`]: ../../std/boxed/struct.Box.html |
41 |
| -/// [`Rc<T>`]: ../../std/rc/struct.Rc.html |
42 |
| -/// [`Vec<T>`]: ../../std/vec/struct.Vec.html |
43 | 49 | /// [`AsRef`]: ../../std/convert/trait.AsRef.html
|
44 | 50 | /// [`BorrowMut`]: trait.BorrowMut.html
|
| 51 | +/// [`Box<T>`]: ../../std/boxed/struct.Box.html |
| 52 | +/// [`Mutex<T>`]: ../../std/sync/struct.Mutex.html |
| 53 | +/// [`Rc<T>`]: ../../std/rc/struct.Rc.html |
| 54 | +/// [`str`]: ../../std/primitive.str.html |
| 55 | +/// [`String`]: ../../std/string/struct.String.html |
45 | 56 | ///
|
46 | 57 | /// # Examples
|
47 | 58 | ///
|
|
85 | 96 | /// ```
|
86 | 97 | ///
|
87 | 98 | /// The entire hash map is generic over a key type `K`. Because these keys
|
88 |
| -/// are stored by with the hash map, this type as to own the key’s data. |
| 99 | +/// are stored with the hash map, this type has to own the key’s data. |
89 | 100 | /// When inserting a key-value pair, the map is given such a `K` and needs
|
90 | 101 | /// to find the correct hash bucket and check if the key is already present
|
91 | 102 | /// based on that `K`. It therefore requires `K: Hash + Eq`.
|
92 | 103 | ///
|
93 |
| -/// In order to search for a value based on the key’s data, the `get` method |
94 |
| -/// is generic over some type `Q`. Technically, it needs to convert that `Q` |
95 |
| -/// into a `K` in order to use `K`’s [`Hash`] implementation to be able to |
96 |
| -/// arrive at the same hash value as during insertion in order to look into |
97 |
| -/// the right hash bucket. Since `K` is some kind of owned value, this likely |
98 |
| -/// would involve cloning and isn’t really practical. |
| 104 | +/// When searching for a value in the map, however, having to provide a |
| 105 | +/// reference to a `K` as the key to search for would require to always |
| 106 | +/// create such an owned value. For string keys, this would mean a `String` |
| 107 | +/// value needs to be created just for the search for cases where only a |
| 108 | +/// `str` is available. |
99 | 109 | ///
|
100 |
| -/// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` |
101 |
| -/// to indicate that `K`’s implementation of `Hash` must produce the same |
102 |
| -/// result as `Q`’s by demanding that `K: Borrow<Q>`. |
| 110 | +/// Instead, the `get` method is generic over the type of the underlying key |
| 111 | +/// data, called `Q` in the method signature above. It states that `K` is a |
| 112 | +/// representation of `Q` by requiring that `K: Borrow<Q>`. By additionally |
| 113 | +/// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have |
| 114 | +/// implementations of the `Hash` and `Eq` traits that procude identical |
| 115 | +/// results. |
| 116 | +/// |
| 117 | +/// The implementation of `get` relies in particular on identical |
| 118 | +/// implementations of `Hash` by determining the key’s hash bucket by calling |
| 119 | +/// `Hash::hash` on the `Q` value even though it inserted the key based on |
| 120 | +/// the hash value calculated from the `K` value. |
103 | 121 | ///
|
104 | 122 | /// As a consequence, the hash map breaks if a `K` wrapping a `Q` value
|
105 | 123 | /// produces a different hash than `Q`. For instance, imagine you have a
|
106 | 124 | /// type that wraps a string but compares ASCII letters ignoring their case:
|
107 | 125 | ///
|
108 | 126 | /// ```
|
109 |
| -/// # #[allow(unused_imports)] |
110 |
| -/// use std::ascii::AsciiExt; |
111 |
| -/// |
112 | 127 | /// pub struct CIString(String);
|
113 | 128 | ///
|
114 | 129 | /// impl PartialEq for CIString {
|
|
124 | 139 | /// implementation of `Hash` needs to reflect that, too:
|
125 | 140 | ///
|
126 | 141 | /// ```
|
127 |
| -/// # #[allow(unused_imports)] use std::ascii::AsciiExt; |
128 | 142 | /// # use std::hash::{Hash, Hasher};
|
129 | 143 | /// # pub struct CIString(String);
|
130 | 144 | /// impl Hash for CIString {
|
|
0 commit comments