6
6
# Summary
7
7
[ summary ] : #summary
8
8
9
- Use an obvious syntax for subslice patterns - ` .. ` and ` ..PAT ` .
10
- If syntactic ambiguities arise in the future, always disambiguate in favor of subslice patterns.
9
+ Permit matching sub-slices and sub-arrays with the syntax ` .. ` .
10
+ Binding a variable to the expression matched by a subslice pattern can be done
11
+ using the existing ` <IDENT> @ <PAT> ` syntax, for example:
12
+
13
+ ``` rust
14
+ // Binding a sub-array:
15
+ let [x , y @ .. , z ] = [1 , 2 , 3 , 4 ]; // `y: [i32, 2] = [2, 3]`
16
+
17
+ // Binding a sub-slice:
18
+ let [x , y @ .. , z ]: & [u8 ] = & [1 , 2 , 3 , 4 ]; // `y: &[i32] = &[2, 3]`
19
+ ```
11
20
12
21
# Motivation
13
22
[ motivation ] : #motivation
@@ -25,7 +34,81 @@ This form is already used in the meaning "rest of the list" in struct patterns,
25
34
patterns and tuple patterns so it would be logical to use it for slice patterns as well.
26
35
And indeed, in unstable Rust ` .. ` is used in this meaning since long before 1.0.
27
36
28
- ### The full form: ` ..PAT ` or ` PAT.. `
37
+ # Guide-level explanation
38
+ [ guide-level-explanation ] : #guide-level-explanation
39
+
40
+ Sub-slices and sub-arrays can be matched using ` .. ` and ` <IDENT> @ .. ` can be used to bind
41
+ these sub-slices and sub-arrays to an identifier.
42
+
43
+ ``` rust
44
+ // Matching slices using `ref` patterns:
45
+ let v = vec! [1 , 2 , 3 ];
46
+ match v [.. ] {
47
+ [1 , ref subslice @ .. , 4 ] => assert_eq! (subslice . len (), 1 ),
48
+ [5 , ref subslice @ .. ] => assert_eq! (subslice . len (), 2 ),
49
+ [ref subslice @ .. , 6 ] => assert_eq! (subslice . len (), 2 ),
50
+ [x , .. , y ] => assert! (v . len () >= 2 ),
51
+ [.. ] => {} // Always matches
52
+ }
53
+
54
+ // Matching slices using default-binding-modes:
55
+ let v = vec! [1 , 2 , 3 ];
56
+ match & v [.. ] {
57
+ [1 , subslice @ .. , 4 ] => assert_eq! (subslice . len (), 1 ),
58
+ [5 , subslice @ .. ] => assert_eq! (subslice . len (), 2 ),
59
+ [subslice @ .. , 6 ] => assert_eq! (subslice . len (), 2 ),
60
+ [x , .. , y ] => assert! (v . len () >= 2 ),
61
+ [.. ] => {} // Always matches
62
+ }
63
+
64
+ // Matching arrays by-value:
65
+ let v = [1 , 2 , 3 ];
66
+ match v {
67
+ [1 , subarray @ .. , 3 ] => assert_eq! (subarray , [2 ]),
68
+ [5 , subarray @ .. ] => has_type :: <[i32 ; 2 ]>(subarray ),
69
+ [subarray @ .. , 6 ] => has_type :: <[i32 , 2 ]>(subarray ),
70
+ [x , .. , y ] => has_type :: <[i32 , 1 ]>(x ),
71
+ [.. ] => {},
72
+ }
73
+ ```
74
+
75
+ # Reference-level explanation
76
+ [ reference-level-explanation ] : #reference-level-explanation
77
+
78
+ ` .. ` can be used as a pattern for matching sub-slices and sub-arrays.
79
+ It is treated as a "non-reference-pattern" for the purpose of determining default-binding-modes,
80
+ and so shifts the binding mode to by-` ref ` or by-` ref mut ` when used to match a subsection of a
81
+ reference or mutable reference to a slice or array.
82
+
83
+ ` @ ` can be used to bind the result of a ` .. ` pattern to an identifier.
84
+
85
+ When used to match against a non-reference slice (` [u8] ` ), ` x @ .. ` would attempt to bind
86
+ by-value, which would fail in the case that users haven't enabled ` feature(unsized_locals) `
87
+ (since otherwise it's not possible to bind ` [u8] ` to a variable directly).
88
+
89
+ # Drawbacks
90
+ [ drawbacks ] : #drawbacks
91
+
92
+ None known.
93
+
94
+ # Rationale and alternatives
95
+ [ alternatives ] : #alternatives
96
+
97
+ The ` PAT.. ` alternative was discussed in the motivational part of the RFC.
98
+
99
+ More complex syntaxes derived from ` .. ` are possible, they use additional tokens to avoid the
100
+ ambiguity with ranges, for example
101
+ [ ` ..PAT.. ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-301485132 ) , or
102
+ [ ` .. @ PAT ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-280920062 ) or
103
+ [ ` PAT @ .. ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-280906823 ) , or other
104
+ similar alternatives.
105
+ We reject these syntaxes because they only bring benefits in incredibly contrived cases using a
106
+ feature that doesn't even exist yet, but normally they only add symbolic noise.
107
+
108
+ More radical syntax changes not keeping consistency with ` .. ` , for example
109
+ [ ` [1, 2, 3, 4] ++ ref v ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-289220169 ) .
110
+
111
+ ### ` ..PAT ` or ` PAT.. `
29
112
30
113
If ` .. ` is used in the meaning "match the subslice (` >=0 ` elements) and ignore it", then it's
31
114
reasonable to expect that syntax for "match the subslice to a pattern" should be some variation
@@ -38,9 +121,7 @@ The issue is that these syntaxes are ambiguous with half-bounded ranges `..END`
38
121
To be precise, such ranges are not currently supported in patterns, but they may be supported in
39
122
the future.
40
123
41
- We argue that this issue is not important and we can choose this syntax for subslice patterns
42
- anyway.
43
- First of all, syntactic ambiguity is not inherently bad, we see it every day in expressions like
124
+ Syntactic ambiguity is not inherently bad. We see it every day in expressions like
44
125
` a + b * c ` . What is important is to disambiguate it reasonably by default and have a way to
45
126
group operands in the alternative way when default disambiguation turns out to be incorrect.
46
127
In case of slice patterns the subslice interpretation seems overwhelmingly more likely, so we
@@ -70,7 +151,7 @@ In 2014 the syntax was changed to `PAT..` by [RFC 202](https://github.com/rust-l
70
151
That RFC received almost no discussion before it got merged and its motivation is no longer
71
152
relevant because arrays now use syntax ` [T; N] ` instead of ` [T, ..N] ` used in old Rust.
72
153
73
- Thus we are proposing to switch back to ` ..PAT ` .
154
+ This RFC originally proposed to switch back to ` ..PAT ` .
74
155
Some reasons to switch:
75
156
- Symmetry with expressions.
76
157
One of the general ideas behind patterns is that destructuring with
@@ -92,67 +173,16 @@ range pattern, then it means that we consumed too much and need to reinterpret t
92
173
somehow. It's probably possible to make this work, but it's some headache that we would like to
93
174
avoid if possible.
94
175
95
- # Guide-level explanation
96
- [ guide-level-explanation ] : #guide-level-explanation
97
-
98
- Subslice (aka "rest of the slice") in a slice patterns can be matched to a pattern ` PAT ` using
99
- syntax ` ..PAT ` .
100
- ` .. ` with the pattern omitted is a sugar for ` .._ ` (wildcard pattern) so it means
101
- "ignore the rest of the slice".
102
-
103
- Example (without ` feature(match_default_bindings) ` ):
104
- ``` rust
105
- let v = vec! [1 , 2 , 3 ];
106
- match v [.. ] {
107
- [1 , .. ref subslice , 4 ] => assert_eq! (subslice . len (), 1 ),
108
- [5 , .. ref subslice ] => assert_eq! (subslice . len (), 2 ),
109
- [.. ref subslice , 6 ] => assert_eq! (subslice . len (), 2 ),
110
- [x , .. , y ] => assert! (v . len () >= 2 ),
111
- [.. ] => {} // Always matches
112
- }
113
- ```
114
- Example (with ` feature(match_default_bindings) ` ):
115
- ``` rust
116
- let v = vec! [1 , 2 , 3 ];
117
- match & v [.. ] {
118
- [1 , .. subslice , 4 ] => assert_eq! (subslice . len (), 1 ),
119
- [5 , .. subslice ] => assert_eq! (subslice . len (), 2 ),
120
- [.. subslice , 6 ] => assert_eq! (subslice . len (), 2 ),
121
- [x , .. , y ] => assert! (v . len () >= 2 ),
122
- [.. ] => {} // Always matches
123
- }
124
- ```
125
-
126
- # Reference-level explanation
127
- [ reference-level-explanation ] : #reference-level-explanation
128
-
129
- Subslice in a slice patterns can be matched to a pattern ` PAT ` using syntax ` ..PAT ` .
130
- ` .. ` with the pattern omitted is a sugar for ` .._ ` .
131
-
132
- If ambiguity with some other syntactic construction arises in the future, disambiguation will be
133
- performed in favor of the subslice pattern.
134
-
135
- # Drawbacks
136
- [ drawbacks ] : #drawbacks
137
-
138
- None known.
139
-
140
- # Rationale and alternatives
141
- [ alternatives ] : #alternatives
142
-
143
- The ` PAT.. ` alternative was discussed in the motivational part of the RFC.
144
-
145
- More complex syntaxes derived from ` .. ` are possible, they use additional tokens to avoid the
146
- ambiguity with ranges, for example
147
- [ ` ..PAT.. ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-301485132 ) , or
148
- [ ` .. @ PAT ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-280920062 ) or
149
- [ ` PAT @ .. ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-280906823 ) , or other
150
- similar alternatives.
151
- We reject these syntaxes because they only bring benefits in incredibly contrived cases using a
152
- feature that doesn't even exist yet, but normally they only add symbolic noise.
176
+ This RFC no longer includes the addition of ` ..PAT ` or ` PAT.. ` , but merely ` .. ` as it results in
177
+ a smaller starting surface-area for the feature which can be expanded in the future if necessary.
178
+ The currently-proposed change is an extremely minimal addition to patterns (` .. ` for slices) which
179
+ already exists in other forms (e.g. tuples) and generalizes well to pattern-matching out sub-tuples,
180
+ e.g. ` let (a, b @ .., c) = (1, 2, 3, 4); ` .
153
181
154
- More radical syntax changes not keeping consistency with ` .. ` , for example
155
- [ ` [1, 2, 3, 4] ++ ref v ` ] ( https://github.com/rust-lang/rust/issues/23121#issuecomment-289220169 ) .
182
+ Additionally, ` @ ` is more consistent with the types of patterns that would be allowable for matching
183
+ slices (only identifiers), whereas ` PAT.. ` /` ..PAT ` suggest the ability to write e.g. ` ..(1, x) ` or
184
+ ` ..SomeStruct { x } ` sub-patterns, which wouldn't be possible since the resulting bound variables
185
+ don't form a slice (since they're spread out in memory).
156
186
157
187
# Prior art
158
188
[ prior-art ] : #prior-art
0 commit comments