mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Update documentation for pattern matching
This commit is contained in:
parent
208f7d7c80
commit
5c0abe2d94
1 changed files with 37 additions and 18 deletions
|
@ -15,15 +15,15 @@ Pattern matching in Ruby is implemented with the +case+/+in+ expression:
|
|||
...
|
||||
end
|
||||
|
||||
(Note that +in+ and +when+ branches can *not* be mixed in one +case+ expression.)
|
||||
(Note that +in+ and +when+ branches can NOT be mixed in one +case+ expression.)
|
||||
|
||||
or with the +=>+ operator and the +in+ operator, which can be used in a standalone expression:
|
||||
or with the <code>=></code> operator and the +in+ operator, which can be used in a standalone expression:
|
||||
|
||||
<expression> => <pattern>
|
||||
|
||||
<expression> in <pattern>
|
||||
|
||||
Pattern matching is _exhaustive_: if variable doesn't match pattern (in a separate +in+ clause), or doesn't matches any branch of +case+ expression (and +else+ branch is absent), +NoMatchingPatternError+ is raised.
|
||||
The +case+/+in+ expression is _exhaustive_: if the value of the expression doesn't match any branch of +case+ expression (and +else+ branch is absent), +NoMatchingPatternError+ is raised.
|
||||
|
||||
Therefore, +case+ expression might be used for conditional matching and unpacking:
|
||||
|
||||
|
@ -39,7 +39,7 @@ Therefore, +case+ expression might be used for conditional matching and unpackin
|
|||
end
|
||||
# Prints: "Connect with user 'admin'"
|
||||
|
||||
whilst the +=>+ operator is most useful when expected data structure is known beforehand, to just unpack parts of it:
|
||||
whilst the <code>=></code> operator is most useful when expected data structure is known beforehand, to just unpack parts of it:
|
||||
|
||||
config = {db: {user: 'admin', password: 'abc123'}}
|
||||
|
||||
|
@ -48,7 +48,7 @@ whilst the +=>+ operator is most useful when expected data structure is known be
|
|||
puts "Connect with user '#{user}'"
|
||||
# Prints: "Connect with user 'admin'"
|
||||
|
||||
+<expression> in <pattern>+ is the same as +case <expression>; in <pattern>; true; else false; end+.
|
||||
<code><expression> in <pattern></code> is the same as <code>case <expression>; in <pattern>; true; else false; end</code>.
|
||||
You can use it when you only want to know if a pattern has been matched or not:
|
||||
|
||||
users = [{name: "Alice", age: 12}, {name: "Bob", age: 23}]
|
||||
|
@ -65,12 +65,12 @@ Patterns can be:
|
|||
* find pattern: <code>[*variable, <subpattern>, <subpattern>, <subpattern>, ..., *variable]</code>; (<em>Find pattern</em>)
|
||||
* hash pattern: <code>{key: <subpattern>, key: <subpattern>, ...}</code>; (<em>Hash pattern</em>)
|
||||
* combination of patterns with <code>|</code>; (<em>Alternative pattern</em>)
|
||||
* variable capture: <code>variable</code> or <code><pattern> => variable</code>; (<em>Variable pattern</em>, <em>As pattern</em>)
|
||||
* variable capture: <code><pattern> => variable</code> or <code>variable</code>; (<em>As pattern</em>, <em>Variable pattern</em>)
|
||||
|
||||
Any pattern can be nested inside array/find/hash patterns where <code><subpattern></code> is specified.
|
||||
|
||||
Array patterns and find patterns match arrays, or objects that respond to +deconstruct+ (see below about the latter).
|
||||
Hash patterns match hashes, or objects that respond to +deconstruct_keys+ (see below about the latter). Note that only symbol keys are supported for hash patterns, at least for now.
|
||||
Hash patterns match hashes, or objects that respond to +deconstruct_keys+ (see below about the latter). Note that only symbol keys are supported for hash patterns.
|
||||
|
||||
An important difference between array and hash patterns behavior is arrays match only a _whole_ array
|
||||
|
||||
|
@ -92,6 +92,24 @@ while the hash matches even if there are other keys besides specified part:
|
|||
end
|
||||
#=> "matched"
|
||||
|
||||
<code>{}</code> is the only exclusion from this rule. It matches iff an empty hash is given:
|
||||
|
||||
case {a: 1, b: 2, c: 3}
|
||||
in {}
|
||||
"matched"
|
||||
else
|
||||
"not matched"
|
||||
end
|
||||
#=> "not matched"
|
||||
|
||||
case {}
|
||||
in {}
|
||||
"matched"
|
||||
else
|
||||
"not matched"
|
||||
end
|
||||
#=> "matched"
|
||||
|
||||
There is also a way to specify there should be no other keys in the matched hash except those explicitly specified by pattern, with <code>**nil</code>:
|
||||
|
||||
case {a: 1, b: 2}
|
||||
|
@ -122,7 +140,7 @@ Both array and hash patterns support "rest" specification:
|
|||
end
|
||||
#=> "matched"
|
||||
|
||||
In +case+ (but not in +=>+ and +in+) expression, parentheses around both kinds of patterns could be omitted
|
||||
In +case+ (but not in <code>=></code> and +in+) expression, parentheses around both kinds of patterns could be omitted:
|
||||
|
||||
case [1, 2]
|
||||
in Integer, Integer
|
||||
|
@ -140,7 +158,7 @@ In +case+ (but not in +=>+ and +in+) expression, parentheses around both kinds o
|
|||
end
|
||||
#=> "matched"
|
||||
|
||||
Find pattern is similar to array pattern but it can be used to check if the given object has any elements that match the pattern.
|
||||
Find pattern is similar to array pattern but it can be used to check if the given object has any elements that match the pattern:
|
||||
|
||||
case ["a", 1, "b", "c", 2]
|
||||
in [*, String, String, *]
|
||||
|
@ -187,7 +205,7 @@ If no additional check is required, only binding some part of the data to a vari
|
|||
end
|
||||
#=> "matched: 1"
|
||||
|
||||
For hash patterns, even a simpler form exists: key-only specification (without any value) binds the local variable with the key's name, too:
|
||||
For hash patterns, even a simpler form exists: key-only specification (without any sub-pattern) binds the local variable with the key's name, too:
|
||||
|
||||
case {a: 1, b: 2, c: 3}
|
||||
in a:
|
||||
|
@ -235,17 +253,17 @@ Binding to variables currently does NOT work for alternative patterns joined wit
|
|||
end
|
||||
# SyntaxError (illegal variable in alternative pattern (a))
|
||||
|
||||
<code>_</code> is the only exclusion from this rule: it still binds the first match to local variable <code>_</code>, but allowed to be used in alternative patterns:
|
||||
Variables that start with <code>_</code> are the only exclusions from this rule:
|
||||
|
||||
case {a: 1, b: 2}
|
||||
in {a: _} | Array
|
||||
"matched: #{_}"
|
||||
in {a: _, b: _foo} | Array
|
||||
"matched: #{_}, #{_foo}"
|
||||
else
|
||||
"not matched"
|
||||
end
|
||||
# => "matched: 1"
|
||||
|
||||
It is, though, not advised to reuse bound value, as <code>_</code> pattern's goal is to signify discarded value.
|
||||
It is, though, not advised to reuse bound value, as these pattern's goal is to signify discarded value.
|
||||
|
||||
== Variable pinning
|
||||
|
||||
|
@ -262,7 +280,7 @@ Due to variable binding feature, existing local variable can't be straightforwar
|
|||
# expected: "not matched. expectation was: 18"
|
||||
# real: "matched. expectation was: 1" -- local variable just rewritten
|
||||
|
||||
For this case, the pin operator <code>^</code> can be used, to tell Ruby "just use this value as a part of pattern"
|
||||
For this case, the pin operator <code>^</code> can be used, to tell Ruby "just use this value as a part of pattern":
|
||||
|
||||
expectation = 18
|
||||
case [1, 2]
|
||||
|
@ -294,9 +312,9 @@ One important usage of variable pinning is specifying the same value should happ
|
|||
end
|
||||
#=> "not matched"
|
||||
|
||||
== Matching non-primitive objects: +deconstruct_keys+ and +deconstruct+
|
||||
== Matching non-primitive objects: +deconstruct+ and +deconstruct_keys+
|
||||
|
||||
As already mentioned above, hash and array/find patterns besides literal arrays and hashes will try to match any object implementing +deconstruct+ (for array/find patterns) or +deconstruct_keys+ (for hash patterns).
|
||||
As already mentioned above, array/find and hash patterns besides literal arrays and hashes will try to match any object implementing +deconstruct+ (for array/find patterns) or +deconstruct_keys+ (for hash patterns).
|
||||
|
||||
class Point
|
||||
def initialize(x, y)
|
||||
|
@ -315,7 +333,7 @@ As already mentioned above, hash and array/find patterns besides literal arrays
|
|||
end
|
||||
|
||||
case Point.new(1, -2)
|
||||
in px, Integer # subpatterns and variable binding works
|
||||
in px, Integer # sub-patterns and variable binding works
|
||||
"matched: #{px}"
|
||||
else
|
||||
"not matched"
|
||||
|
@ -418,6 +436,7 @@ So, only subsequently loaded files or `eval`-ed code is affected by switching th
|
|||
Alternatively, command-line key <code>-W:no-experimental</code> can be used to turn off "experimental" feature warnings.
|
||||
|
||||
== Appendix A. Pattern syntax
|
||||
|
||||
Approximate syntax is:
|
||||
|
||||
pattern: value_pattern
|
||||
|
|
Loading…
Add table
Reference in a new issue