@@ -22,34 +22,71 @@ Various changes to the match ergonomics rules:
22
22
Match ergonomics have been a great success overall, but there are some surprising
23
23
interactions that regularly confuse users.
24
24
25
- - ` mut ` resets the binding mode to by-value, which users do not expect; the
26
- mutability of the binding seems like a separate concern from its type
27
- (< https://github.com/rust-lang/rust/issues/105647 > ,
28
- < https://github.com/rust-lang/rust/issues/112545 > )
29
- - ` & ` and ` &mut ` patterns must correspond with a reference in the same position
30
- in the scrutinee, even if there is an inherited reference present. Therefore,
31
- users have no general mechanism to "cancel out" an inherited reference
32
- (< https://users.rust-lang.org/t/reference-of-tuple-and-tuple-of-reference/91713/6 > ,
33
- < https://users.rust-lang.org/t/cannot-deconstruct-reference-inside-match-on-reference-why/92147 > ,
34
- < https://github.com/rust-lang/rust/issues/50008 > ,
35
- < https://github.com/rust-lang/rust/issues/64586 > )
36
- - When an ` & ` or ` &mut ` pattern is used in a location where there is also an
37
- inherited reference present, both are stripped; adding a single ` & ` to the
38
- pattern can remove two ` & ` s from the type of the binding.
25
+ ## ` mut ` resets the binding mode
26
+
27
+ ` mut ` resets the binding mode to by-value, which users do not expect; the
28
+ mutability of the binding would seem to be separate concern from its type
29
+ (< https://github.com/rust-lang/rust/issues/105647 > ,
30
+ < https://github.com/rust-lang/rust/issues/112545 > ).
31
+
32
+ ``` rust
33
+ let (x , mut y ) = & (true , false );
34
+ let _ : (& bool , bool ) = (x , y );
35
+ ```
36
+
37
+ ## Can't cancel out an inherited reference
38
+
39
+ ` & ` and ` &mut ` patterns must correspond with a reference in the same position in
40
+ the scrutinee, even if there is an inherited reference present. Therefore, users
41
+ have no general mechanism to "cancel out" an inherited reference
42
+ (< https://users.rust-lang.org/t/reference-of-tuple-and-tuple-of-reference/91713/6 > ,
43
+ < https://users.rust-lang.org/t/cannot-deconstruct-reference-inside-match-on-reference-why/92147 > ,
44
+ < https://github.com/rust-lang/rust/issues/50008 > ,
45
+ < https://github.com/rust-lang/rust/issues/64586 > ).
46
+
47
+
48
+ ``` rust
49
+ fn foo (arg : & (String , Vec <i32 >, u8 )) {
50
+ // We want to extract `&String`, `&Vec`, and `u8` from the tuple.
51
+ let (s , v , u ) = arg ; // u is &u8, not what we wanted
52
+ let & (ref s , ref v , u ) = arg ; // we have to abandon match ergonomics entirely
53
+ }
54
+ ```
55
+
56
+ ## A single ` & ` can strip two references
57
+
58
+ When an ` & ` or ` &mut ` pattern is used in a location where there is also an
59
+ inherited reference present, both are stripped; adding a single ` & ` to the
60
+ pattern can remove two ` & ` s from the type of the binding.
61
+
62
+ ``` rust
63
+ let [a ] = & [& 42 ]; // a = &&42
64
+ let [& a ] = & [& 42 ]; // a = 42
65
+ ```
39
66
40
67
# Guide-level explanation
41
68
[ guide-level-explanation ] : #guide-level-explanation
42
69
43
70
Match ergonomics works a little differently in edition 2024 and above.
44
71
72
+ ## ` mut ` no longer strips the inherited reference
73
+
74
+ ` mut ` on a binding does not reset the binding mode on edition ≥ 2024.
75
+
76
+ ``` rust
77
+ // ! Edition ≥ 2024
78
+ let (x , mut y ) = & (true , false );
79
+ let _ : (& bool , & bool ) = (x , y ); // instead of `(&bool, bool)`
80
+ ```
81
+
45
82
## Matching against inherited references
46
83
47
84
In all editions, when you match against an ` & ` or ` &mut ` reference with the type
48
85
of its referent, you get an "inherited reference": the binding mode of
49
86
"downstream" bindings is set to ` ref ` or ` ref mut ` .
50
87
51
88
``` rust
52
- // Unchanged from old editions:
89
+ // ! All editions
53
90
// `x` "inherits" the `&` from the scrutinee type.
54
91
let [x ] = & [42 ];
55
92
let _ : & u8 = x ;
@@ -59,10 +96,21 @@ In edition 2024 and above, an `&` or `&mut` pattern can match against this
59
96
inherited reference, consuming it. A pattern that does this has no other effect.
60
97
61
98
``` rust
62
- // New in edition 2024:
99
+ // ! Edition ≥ 2024
100
+
63
101
// `&` pattern consumes inherited `&` reference.
64
102
let [& x ] = & [42 ];
65
103
let _ : u8 = x ;
104
+
105
+ // Examples from motivation section
106
+
107
+ fn foo (arg : & (String , Vec <i32 >, u8 )) {
108
+ let (s , v , & u ) = arg ;
109
+ let _ : (& String , & Vec <i32 >, u8 ) = (s , v , u );
110
+ }
111
+
112
+ let [& x ] = & [& 42 ];
113
+ let _ : & u8 = x ;
66
114
```
67
115
68
116
## ` & ` matches against ` &mut `
@@ -71,49 +119,45 @@ In edition 2024 and above, `&` patterns can match against `&mut` references
71
119
(including "inherited" references).
72
120
73
121
``` rust
122
+ // ! Edition ≥ 2024
74
123
let & foo = & mut 42 ;
75
124
let _ : u8 = foo ;
76
125
```
77
126
78
- ## ` mut ` no longer strips the inherited reference
79
-
80
- In older editions, ` mut ` on a binding "stripped" the inherited reference:
127
+ # Reference-level explanation
128
+ [ reference-level-explanation ] : #reference-level-explanation
81
129
82
- ``` rust
83
- // Old editions
84
- let (x , mut y ) = & (true , false );
85
- let _ : (& bool , bool ) = (x , y );
86
- ```
130
+ This explanation assumes familiarity with the current match ergonomics rules,
131
+ including the "default binding mode" terminology. Refer to [ RFC 2005] ( ./2005-match-ergonomics.md#detailed-design ) .
87
132
88
- This no longer happens on edition ≥ 2024.
133
+ ## Edition 2024: ` mut ` does not reset binding mode to by-value
89
134
135
+ In the new edition, ` mut ` no longer resets the binding mode to by-value.
136
+ Therefore, it is possible to have a mutable by-reference binding. (An explicit
137
+ syntax for this is left to a future RFC.)
90
138
91
139
``` rust
92
- // Edition ≥ 2024
93
- let ( x , mut y ) = & ( true , false ) ;
94
- let _ : ( & bool , & bool ) = ( x , y ) ;
140
+ // ! Edition ≥ 2024
141
+ let & [ mut a ] = & [ 42 ] ;
142
+ a = & 47 ;
95
143
```
96
144
97
- # Reference-level explanation
98
- [ reference-level-explanation ] : #reference-level-explanation
99
-
100
- This explanation assumes familiarity with the current match ergonomics rules,
101
- including the "default binding mode" terminology. Refer to [ RFC 2005] ( ./2005-match-ergonomics.md#detailed-design ) .
102
-
103
145
## Edition 2024: ` & ` patterns can match against ` &mut ` references
104
146
105
147
` & ` patterns can match against ` &mut ` references.
106
148
107
149
``` rust
150
+ // ! Edition ≥ 2024
108
151
let & foo = & mut 42 ;
109
152
let _ : u8 = foo ;
110
153
```
111
154
112
155
However, the ` ref mut ` binding mode cannot be used behind such patterns.
113
156
114
157
``` rust
158
+ // ! All editions
115
159
let & ref mut foo = & mut 42 ;
116
- // ^~ERROR: replace `&` with `&mut`
160
+ // ^~ERROR: replace `&` with `&mut `
117
161
let _ : & mut u8 = foo ;
118
162
```
119
163
@@ -125,6 +169,8 @@ by-value, while `&mut` can only reset `ref mut`. An `&` or `&mut` pattern that
125
169
resets the binding mode in this way has no other effect.
126
170
127
171
``` rust
172
+ // ! Edition ≥ 2024
173
+
128
174
let [& x ] = & [3u8 ];
129
175
let _ : u8 = x ;
130
176
@@ -133,13 +179,18 @@ let _: u8 = x;
133
179
134
180
let [& x ] = & mut [3u8 ];
135
181
let _ : u8 = x ;
182
+ ```
136
183
184
+ ``` rust
185
+ // ! All editions
137
186
// let [&mut x] = &[3u8]; // ERROR
138
187
```
139
188
140
189
` & ` patterns are otherwise unchanged from older editions.
141
190
142
191
``` rust
192
+ // ! All editions
193
+
143
194
let & a = & 3 ;
144
195
let _ : u8 = a ;
145
196
@@ -150,9 +201,12 @@ If the default binding mode is `ref`, then `&mut` patterns are forbidden. If it
150
201
is by-value, then they have the same effect as on older editions.
151
202
152
203
``` rust
204
+ // ! Edition ≥ 2024
153
205
// let [&mut x] = &[&mut 42]; // ERROR
206
+ ```
154
207
155
- // Unchanged from old editions
208
+ ``` rust
209
+ // ! All editions
156
210
157
211
let & mut x = & mut 3 ;
158
212
let _ : u8 = x ;
@@ -166,24 +220,13 @@ let _: &&mut u8 = x;
166
220
// let &mut x = &&mut 3; // ERROR
167
221
```
168
222
169
- ## Edition 2024: ` mut ` does not reset binding mode to by-value
170
-
171
- In the new edition, ` mut ` no longer resets the binding mode to by-value.
172
- Therefore, it is possible to have a mutable by-reference binding. (An explicit
173
- syntax for this is left to a future RFC.)
174
-
175
- ``` rust
176
- let & [mut a ] = & [42 ];
177
- a = & 47 ;
178
- ```
179
-
180
223
## All editions: the default binding mode is never set to ` ref mut ` behind an ` & ` pattern or reference
181
224
182
225
The binding mode is set to ` ref ` instead in such cases. (On older editions, this
183
226
allows strictly more code to compile.)
184
227
185
228
``` rust
186
- // All editions
229
+ // ! All editions (new)
187
230
188
231
let & [[a ]]; = & [& mut [42 ]];
189
232
let _ : & u8 = a ;
@@ -193,7 +236,7 @@ let _: &u8 = a;
193
236
```
194
237
195
238
``` rust
196
- // Edition ≥ 2024
239
+ // ! Edition ≥ 2024
197
240
198
241
let & [[& a ]]; = & [& mut [42 ]];
199
242
let _ : u8 = a ;
@@ -319,7 +362,7 @@ explicit `ref` is required. Notably, this can occur where `&mut` is nested
319
362
behind ` & ` :
320
363
321
364
``` rust
322
- // No way to avoid the `ref` here currently
365
+ // No way to avoid the `ref`, even with this RFC
323
366
let & [& mut ref x ] = & [& mut 42 ];
324
367
```
325
368
0 commit comments