]>
Commit | Line | Data |
---|---|---|
bd371182 AL |
1 | % Borrow and AsRef |
2 | ||
3 | The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but | |
4 | different. Here’s a quick refresher on what these two traits mean. | |
5 | ||
6 | [borrow]: ../std/borrow/trait.Borrow.html | |
7 | [asref]: ../std/convert/trait.AsRef.html | |
8 | ||
9 | # Borrow | |
10 | ||
9e0c209e | 11 | The `Borrow` trait is used when you’re writing a data structure, and you want to |
bd371182 AL |
12 | use either an owned or borrowed type as synonymous for some purpose. |
13 | ||
14 | For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: | |
15 | ||
16 | ```rust,ignore | |
17 | fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> | |
18 | where K: Borrow<Q>, | |
19 | Q: Hash + Eq | |
20 | ``` | |
21 | ||
22 | [hashmap]: ../std/collections/struct.HashMap.html | |
23 | [get]: ../std/collections/struct.HashMap.html#method.get | |
24 | ||
25 | This signature is pretty complicated. The `K` parameter is what we’re interested | |
26 | in here. It refers to a parameter of the `HashMap` itself: | |
27 | ||
28 | ```rust,ignore | |
29 | struct HashMap<K, V, S = RandomState> { | |
30 | ``` | |
31 | ||
32 | The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at | |
33 | the signature of `get()` again, we can use `get()` when the key implements | |
34 | `Borrow<Q>`. That way, we can make a `HashMap` which uses `String` keys, | |
35 | but use `&str`s when we’re searching: | |
36 | ||
37 | ```rust | |
38 | use std::collections::HashMap; | |
39 | ||
40 | let mut map = HashMap::new(); | |
41 | map.insert("Foo".to_string(), 42); | |
42 | ||
43 | assert_eq!(map.get("Foo"), Some(&42)); | |
44 | ``` | |
45 | ||
46 | This is because the standard library has `impl Borrow<str> for String`. | |
47 | ||
48 | For most types, when you want to take an owned or borrowed type, a `&T` is | |
49 | enough. But one area where `Borrow` is effective is when there’s more than one | |
62682a34 SL |
50 | kind of borrowed value. This is especially true of references and slices: you |
51 | can have both an `&T` or a `&mut T`. If we wanted to accept both of these types, | |
52 | `Borrow` is up for it: | |
bd371182 | 53 | |
62682a34 | 54 | ```rust |
bd371182 AL |
55 | use std::borrow::Borrow; |
56 | use std::fmt::Display; | |
57 | ||
58 | fn foo<T: Borrow<i32> + Display>(a: T) { | |
59 | println!("a is borrowed: {}", a); | |
60 | } | |
61 | ||
62 | let mut i = 5; | |
63 | ||
64 | foo(&i); | |
65 | foo(&mut i); | |
66 | ``` | |
67 | ||
68 | This will print out `a is borrowed: 5` twice. | |
69 | ||
70 | # AsRef | |
71 | ||
72 | The `AsRef` trait is a conversion trait. It’s used for converting some value to | |
73 | a reference in generic code. Like this: | |
74 | ||
75 | ```rust | |
76 | let s = "Hello".to_string(); | |
77 | ||
78 | fn foo<T: AsRef<str>>(s: T) { | |
79 | let slice = s.as_ref(); | |
80 | } | |
81 | ``` | |
82 | ||
83 | # Which should I use? | |
84 | ||
85 | We can see how they’re kind of the same: they both deal with owned and borrowed | |
86 | versions of some type. However, they’re a bit different. | |
87 | ||
88 | Choose `Borrow` when you want to abstract over different kinds of borrowing, or | |
9e0c209e | 89 | when you’re building a data structure that treats owned and borrowed values in |
bd371182 AL |
90 | equivalent ways, such as hashing and comparison. |
91 | ||
92 | Choose `AsRef` when you want to convert something to a reference directly, and | |
93 | you’re writing generic code. |