Skip to content

Commit 7ae7e53

Browse files
committed
New introduction and revised hash map explanation.
1 parent fc6c638 commit 7ae7e53

File tree

1 file changed

+44
-30
lines changed

1 file changed

+44
-30
lines changed

src/libcore/borrow.rs

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,28 @@
1414

1515
/// A trait identifying how borrowed data behaves.
1616
///
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>`.
3039
///
3140
/// When writing generic code, a use of `Borrow` should always be justified
3241
/// by additional trait bounds, making it clear that the two types need to
@@ -37,11 +46,13 @@
3746
/// The companion trait [`BorrowMut`] provides the same guarantees for
3847
/// mutable references.
3948
///
40-
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
41-
/// [`Rc<T>`]: ../../std/rc/struct.Rc.html
42-
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
4349
/// [`AsRef`]: ../../std/convert/trait.AsRef.html
4450
/// [`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
4556
///
4657
/// # Examples
4758
///
@@ -85,30 +96,34 @@
8596
/// ```
8697
///
8798
/// 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.
89100
/// When inserting a key-value pair, the map is given such a `K` and needs
90101
/// to find the correct hash bucket and check if the key is already present
91102
/// based on that `K`. It therefore requires `K: Hash + Eq`.
92103
///
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.
99109
///
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.
103121
///
104122
/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value
105123
/// produces a different hash than `Q`. For instance, imagine you have a
106124
/// type that wraps a string but compares ASCII letters ignoring their case:
107125
///
108126
/// ```
109-
/// # #[allow(unused_imports)]
110-
/// use std::ascii::AsciiExt;
111-
///
112127
/// pub struct CIString(String);
113128
///
114129
/// impl PartialEq for CIString {
@@ -124,7 +139,6 @@
124139
/// implementation of `Hash` needs to reflect that, too:
125140
///
126141
/// ```
127-
/// # #[allow(unused_imports)] use std::ascii::AsciiExt;
128142
/// # use std::hash::{Hash, Hasher};
129143
/// # pub struct CIString(String);
130144
/// impl Hash for CIString {

0 commit comments

Comments
 (0)