|
12 | 12 |
|
13 | 13 | #![stable(feature = "rust1", since = "1.0.0")]
|
14 | 14 |
|
15 |
| -/// A trait for borrowing data. |
| 15 | +// impl Borrow<str> for String |
| 16 | +// impl<T> Borrow<T> for Arc<T> |
| 17 | +// impl<K> HashSet<K> { fn get<Q>(&self, q: &Q) where K: Borrow<Q> } |
| 18 | + |
| 19 | +/// A trait identifying how borrowed data behaves. |
| 20 | +/// |
| 21 | +/// If a type implements this trait, it signals that a reference to it behaves |
| 22 | +/// exactly like a reference to `Borrowed`. As a consequence, if a trait is |
| 23 | +/// implemented both by `Self` and `Borrowed`, all trait methods that |
| 24 | +/// take a `&self` argument must produce the same result in both |
| 25 | +/// implementations. |
| 26 | +/// |
| 27 | +/// As a consequence, this trait should only be implemented for types managing |
| 28 | +/// a value of another type without modifying its behavior. Examples are |
| 29 | +/// smart pointers such as [`Box`] or [`Rc`] as well the owned version of |
| 30 | +/// slices such as [`Vec`]. |
| 31 | +/// |
| 32 | +/// A relaxed version that allows providing a reference to some other type |
| 33 | +/// without any further promises is available through [`AsRef`]. |
| 34 | +/// |
| 35 | +/// When writing generic code, a use of `Borrow` should always be justified |
| 36 | +/// by additional trait bounds, making it clear that the two types need to |
| 37 | +/// behave identically in a certain context. If the code should merely be |
| 38 | +/// able to operate on any type that can produce a reference to a given type, |
| 39 | +/// you should use [`AsRef`] instead. |
| 40 | +/// |
| 41 | +/// The companion trait [`BorrowMut`] provides the same guarantees for |
| 42 | +/// mutable references. |
| 43 | +/// |
| 44 | +/// [`Box`]: ../boxed/struct.Box.html |
| 45 | +/// [`Rc`]: ../rc/struct.Rc.html |
| 46 | +/// [`Vec`]: ../vec/struct.Vec.html |
| 47 | +/// [`AsRef`]: ../convert/trait.AsRef.html |
| 48 | +/// [`BorrowMut`]: trait.BorrowMut.html |
| 49 | +/// |
| 50 | +/// # Examples |
| 51 | +/// |
| 52 | +/// As a data collection, [`HashMap`] owns both keys and values. If the key’s |
| 53 | +/// actual data is wrapped in a managing type of some kind, it should, |
| 54 | +/// however, still be possible to search for a value using a reference to the |
| 55 | +/// key’s data. For instance, if the key is a string, then it is likely |
| 56 | +/// stored with the hash map as a [`String`], while it should be possible |
| 57 | +/// to search using a [`&str`][`str`]. Thus, `insert` needs to operate on a |
| 58 | +/// string while `get` needs to be able to use a `&str`. |
| 59 | +/// |
| 60 | +/// Slightly simplified, the relevant parts of `HashMap` look like this: |
| 61 | +/// |
| 62 | +/// ``` |
| 63 | +/// use std::borrow::Borrow; |
| 64 | +/// use std::hash::Hash; |
| 65 | +/// |
| 66 | +/// pub struct HashMap<K, V> { |
| 67 | +/// # marker: ::std::marker::PhantomData<(K, V)>, |
| 68 | +/// // fields omitted |
| 69 | +/// } |
| 70 | +/// |
| 71 | +/// impl<K, V> HashMap<K, V> { |
| 72 | +/// pub fn insert(&self, key: K, value: V) -> Option<V> |
| 73 | +/// where K: Hash + Eq |
| 74 | +/// { |
| 75 | +/// # unimplemented!() |
| 76 | +/// // ... |
| 77 | +/// } |
| 78 | +/// |
| 79 | +/// pub fn get<Q>(&self, k: &Q) -> Option<&V> |
| 80 | +/// where K: Borrow<Q>, |
| 81 | +/// Q: Hash + Eq + ?Sized |
| 82 | +/// { |
| 83 | +/// # unimplemented!() |
| 84 | +/// // ... |
| 85 | +/// } |
| 86 | +/// } |
| 87 | +/// ``` |
| 88 | +/// |
| 89 | +/// The entire hash map is generic over the stored type for the key, `K`. |
| 90 | +/// When inserting a value, the map is given such a `K` and needs to find |
| 91 | +/// the correct hash bucket and check if the key is already present based |
| 92 | +/// on that `K` value. It therefore requires `K: Hash + Eq`. |
| 93 | +/// |
| 94 | +/// In order to search for a value based on the key’s data, the `get` method |
| 95 | +/// is generic over some type `Q`. Technically, it needs to convert that `Q` |
| 96 | +/// into a `K` in order to use `K`’s [`Hash`] implementation to be able to |
| 97 | +/// arrive at the same hash value as during insertion in order to look into |
| 98 | +/// the right hash bucket. Since `K` is some kind of owned value, this likely |
| 99 | +/// would involve cloning and isn’t really practical. |
| 100 | +/// |
| 101 | +/// Instead, `get` relies on `Q`’s implementation of `Hash` and uses `Borrow` |
| 102 | +/// to indicate that `K`’s implementation of `Hash` must produce the same |
| 103 | +/// result as `Q`’s by demanding that `K: Borrow<Q>`. |
| 104 | +/// |
| 105 | +/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value |
| 106 | +/// produces a different hash than `Q`. For instance, image you have a |
| 107 | +/// type that wraps a string but compares ASCII letters case-insensitive: |
| 108 | +/// |
| 109 | +/// ``` |
| 110 | +/// use std::ascii::AsciiExt; |
| 111 | +/// |
| 112 | +/// pub struct CIString(String); |
| 113 | +/// |
| 114 | +/// impl PartialEq for CIString { |
| 115 | +/// fn eq(&self, other: &Self) -> bool { |
| 116 | +/// self.0.eq_ignore_ascii_case(&other.0) |
| 117 | +/// } |
| 118 | +/// } |
16 | 119 | ///
|
17 |
| -/// In general, there may be several ways to "borrow" a piece of data. The |
18 |
| -/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T` |
19 |
| -/// (a mutable borrow). But types like `Vec<T>` provide additional kinds of |
20 |
| -/// borrows: the borrowed slices `&[T]` and `&mut [T]`. |
| 120 | +/// impl Eq for CIString { } |
| 121 | +/// ``` |
21 | 122 | ///
|
22 |
| -/// When writing generic code, it is often desirable to abstract over all ways |
23 |
| -/// of borrowing data from a given type. That is the role of the `Borrow` |
24 |
| -/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`. A given |
25 |
| -/// type can be borrowed as multiple different types. In particular, `Vec<T>: |
26 |
| -/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`. |
| 123 | +/// Because two equal values need to produce the same hash value, the |
| 124 | +/// implementation of `Hash` need to reflect that, too: |
27 | 125 | ///
|
28 |
| -/// If you are implementing `Borrow` and both `Self` and `Borrowed` implement |
29 |
| -/// `Hash`, `Eq`, and/or `Ord`, they must produce the same result. |
| 126 | +/// ``` |
| 127 | +/// # use std::ascii::AsciiExt; |
| 128 | +/// # use std::hash::{Hash, Hasher}; |
| 129 | +/// # pub struct CIString(String); |
| 130 | +/// impl Hash for CIString { |
| 131 | +/// fn hash<H: Hasher>(&self, state: &mut H) { |
| 132 | +/// for c in self.0.as_bytes() { |
| 133 | +/// c.to_ascii_lowercase().hash(state) |
| 134 | +/// } |
| 135 | +/// } |
| 136 | +/// } |
| 137 | +/// ``` |
30 | 138 | ///
|
31 |
| -/// `Borrow` is very similar to, but different than, `AsRef`. See |
32 |
| -/// [the book][book] for more. |
| 139 | +/// Can `CIString` implement `Borrow<str>`? It certainly can provide a |
| 140 | +/// reference to a string slice via its contained owned string. But because |
| 141 | +/// its `Hash` implementation differs, it cannot fulfill the guarantee for |
| 142 | +/// `Borrow` that all common trait implementations must behave the same way |
| 143 | +/// and must not, in fact, implement `Borrow<str>`. If it wants to allow |
| 144 | +/// others access to the underlying `str`, it can do that via `AsRef<str>` |
| 145 | +/// which doesn’t carry any such restrictions. |
33 | 146 | ///
|
34 |
| -/// [book]: ../../book/first-edition/borrow-and-asref.html |
| 147 | +/// [`Hash`]: ../hash/trait.Hash.html |
| 148 | +/// [`HashMap`]: ../collections/struct.HashMap.html |
| 149 | +/// [`String`]: ../string/struct.String.html |
| 150 | +/// [`str`]: ../primitive.str.html |
| 151 | +/// |
35 | 152 | #[stable(feature = "rust1", since = "1.0.0")]
|
36 | 153 | pub trait Borrow<Borrowed: ?Sized> {
|
37 | 154 | /// Immutably borrows from an owned value.
|
|
0 commit comments