@@ -19,9 +19,7 @@ is *already* in the map, and when it's *not*. One way to do this is the followin
19
19
20
20
```
21
21
if map.contains_key(&key) {
22
- let v = map.find_mut(&key).unwrap();
23
- let new_v = *v + 1;
24
- *v = new_v;
22
+ *map.find_mut(&key).unwrap() += 1;
25
23
} else {
26
24
map.insert(key, 1);
27
25
}
@@ -58,8 +56,8 @@ composability. Thus, this RFC proposes the same solution to the internal mutatio
58
56
# Detailed design
59
57
60
58
A fully tested "proof of concept" draft of this design has been implemented on top of hashmap,
61
- as it seems to be the worst offender, while still being easy to work with. You can
62
- [ read the diff here] ( https://github.com/Gankro /rust/commit/39a1fa7c7362a3e22e59ab6601ac09475daff39b ) .
59
+ as it seems to be the worst offender, while still being easy to work with. It sits as a pull request
60
+ [ here] ( https://github.com/rust-lang /rust/pull/17378 ) .
63
61
64
62
All the internal mutation methods are replaced with a single method on a collection: ` entry ` .
65
63
The signature of ` entry ` will depend on the specific collection, but generally it will be similar to
@@ -87,26 +85,29 @@ pub enum Entry<'a, K, V> {
87
85
}
88
86
```
89
87
90
- Of course, the real meat of the API is in the View 's interface (impl details removed):
88
+ Of course, the real meat of the API is in the Entry 's interface (impl details removed):
91
89
92
90
```
93
91
impl<'a, K, V> OccupiedEntry<'a, K, V> {
94
- /// Get a reference to the value of this Entry
92
+ /// Gets a reference to the value of this Entry
95
93
pub fn get(&self) -> &V;
96
94
97
- /// Get a mutable reference to the value of this Entry
95
+ /// Gets a mutable reference to the value of this Entry
98
96
pub fn get_mut(&mut self) -> &mut V;
99
97
100
- /// Set the value stored in this Entry
101
- pub fn set(mut self, value: V ) -> V;
98
+ /// Converts the entry into a mutable reference to its value
99
+ pub fn into_mut( self) -> &'a mut V;
102
100
103
- /// Take the value stored in this Entry
101
+ /// Sets the value stored in this Entry
102
+ pub fn set(&mut self, value: V) -> V;
103
+
104
+ /// Takes the value stored in this Entry
104
105
pub fn take(self) -> V;
105
106
}
106
107
107
108
impl<'a, K, V> VacantEntry<'a, K, V> {
108
- /// Set the value stored in this Entry
109
- pub fn set(self, value: V);
109
+ /// Set the value stored in this Entry, and returns a reference to it
110
+ pub fn set(self, value: V) -> &'a mut V ;
110
111
}
111
112
```
112
113
@@ -129,27 +130,35 @@ the guarantor, and destroy the Entry. This is to avoid the costs of maintaining
129
130
otherwise isn't particularly interesting anymore.
130
131
131
132
If there is a match, a more robust set of options is provided. ` get ` and ` get_mut ` provide access to the
132
- value found in the location. ` set ` behaves as the vacant variant, but also yields the old value. ` take `
133
- simply removes the found value, and destroys the entry for similar reasons as ` set ` .
133
+ value found in the location. ` set ` behaves as the vacant variant, but without destroying the entry.
134
+ It also yields the old value. ` take ` simply removes the found value, and destroys the entry for similar reasons as ` set ` .
134
135
135
136
Let's look at how we one now writes ` insert_or_update ` :
136
137
138
+ There are two options. We can either do the following:
139
+
140
+ ```
141
+ // cleaner, and more flexible if logic is more complex
142
+ let val = match map.entry(key) {
143
+ Vacant(entry) => entry.set(0),
144
+ Occupied(entry) => entry.into_mut(),
145
+ };
146
+ *val += 1;
147
+ ```
148
+
149
+ or
150
+
137
151
```
152
+ // closer to the original, and more compact
138
153
match map.entry(key) {
139
- Occupied(entry) => {
140
- let v = entry.get_mut();
141
- let new_v = *v + 1;
142
- *v = new_v;
143
- }
144
- Vacant(entry) => {
145
- entry.set(1);
146
- }
154
+ Vacant(entry) => { entry.set(1); },
155
+ Occupied(mut entry) => { *entry.get_mut() += 1; },
147
156
}
148
157
```
149
158
150
- One can now write something equivalent to the "intuitive" inefficient code, but it is now as efficient as the complex
159
+ Either way, one can now write something equivalent to the "intuitive" inefficient code, but it is now as efficient as the complex
151
160
` insert_or_update ` methods. In fact, this matches so closely to the inefficient manipulation
152
- that users could reasonable ignore Entries * until performance becomes an issue* . At which point
161
+ that users could reasonable ignore Entries * until performance becomes an issue* , at which point
153
162
it's an almost trivial migration. Closures also aren't needed to dance around the fact that one may
154
163
want to avoid generating some values unless they have to, because that falls naturally out of
155
164
normal control flow.
@@ -195,11 +204,5 @@ However it had some interesting ideas about Key manipulation, so we mention it h
195
204
historical purposes.
196
205
197
206
# Unresolved questions
198
- The internal mutation methods cannot actually be implemented in terms of the View, because
199
- they return a mutable reference at the end, and there's no way to do that with the current
200
- View design. However, it's not clear why this is done by them. We believe it's simply to
201
- validate what the method * actually did* . If this is the case, then Views make this functionality
202
- obsolete. However, if this is * still* desirable, ` set ` could be tweaked to do this as well.
203
- However for some structures it may incur additional cost. Is this desirable functionality?
204
207
205
208
Naming bikesheds!
0 commit comments