RubyKaigi2019ã§èããRuby2.7ããå
¥ãPattern Matchã®æ©è½ã«æåããã®ã§ãããã»ãã·ã§ã³ä¸ã¯ç解ããããªãé¨åããã£ãã®ã§ãã¹ã©ã¤ããèªã¿ãã³ã¼ããåããã¦ã¿ã¾ããã
ããããæ¹ãã¦æåãããã¨ããè¨äºã§ãï¼
ã¹ã©ã¤ãã®ã¯ããã«ãä¸è¨ã®è¨è¼ãããã¾ãã
- PatternMatchingã¯2.7.0ããã®æ°æ©è½ã§ãããtrunkã«ã¯ããcommitæ¸
- ä»æ§ã¯ã¾ã çå®ä¸
- 試ãã¦ãã£ã¼ãããã¯ãã ãããï¼
ãªããgithubã«ãµã³ãã«ã³ã¼ããç½®ãã¦ãã¾ãã
1. æºå
Ruby2.7.0(dev)ã¯ãã«ãããªããããªâ¦ã¨æã£ã¦ããrbenvããã対å¿ãã¦ã¾ããã
ã¯ããï¼ããããï¼
$ brew upgrade rbenv ruby-build
ããã§ç¡äº2.7.0-dev
ããªã¹ãã«åºã¦ããããã«ãªãã¾ãã
$ rbenv install --list (ç¥) 2.6.1 2.6.2 2.6.3 2.7.0-dev (ç¥) $ rbenv install 2.7.0-dev (ç¥) Installed ruby-trunk to /Users/makicamel/.rbenv/versions/2.7.0-dev $ rbenv versions * system 2.7.0-dev $ rbenv local 2.7.0-dev $ rbenv version 2.7.0-dev (set by /Users/makicamel/pattern_match/.ruby-version)
ããã§æºåå®äºã§ãï¼
試ãã«PatternMatchingãæ¸ãã¦ã¿ãã¨åãããã«ãªãã¾ããï¼
ãã®æwarningãåºãã®ã§ãããã»ãã¨éçºä¸ã£ã¦æããããããããã¾ãâ¦ï¼
warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
2. PatternMatchingã¨ã¯ï¼
case
å¥ã«å¯¾ãã¦è¤æ°ã®å¤ãå²ãå½ã¦ããããã¨ã
å¾æ¥ã®case
å¥ã£ã¦ãããªæããå®å
¨ä¸è´ã§ãã
case [0, [1, 2, 3]] when [0] :unreachable when [0, [1]] :unreachable when [0, [1, 2, 3]] p 'here' end # => here
PatternMatchingãå°å
¥ãããã¨ãããªãã¾ãã(in
ç¯ã«ãªãã¾ã)
case [0, [1, 2, 3]] in [0, [1]] :unreachable in [a, b] p a # => 0 p b # => [1, 2, 3] in [0, [1, 2, 3]] :unreachable end
ãã¿ã¼ã³ããããããã ãã§ãªãããããããå¤æ°åã§ãã®ã¾ã¾ãããããå¤ãåãåºãã¾ãã
*
(ã¹ãã©ããæ¼ç®å)ã使ã£ã¦ãããªé¢¨ã«ãããã¾ãã
case [0, [1, 2, 3]] in [a, [b, *c]] p a # => 0 p b # => 1 p c # => [2, 3] end
ã¡ããã¨æ§é ããã§ãã¯ãã¦ãããã®ã§ããããªãã¾ãã
case [0, [1, 2, 3]] in [a] :unreachable in a p a # => [0, [1, 2, 3]] end
ããã·ã¥ã使ãã¾ãã
case {a: 0, b: 1} in {a: 0, x: 1} :unreachable in {a: 0, b: var} p var # => 1 end
ããã使ãæããããï¼
ã»ãã·ã§ã³ã«ããã¨ãJSONã®ãã¼ã¿ãæ±ãæã«ä¾¿å©ã§ãããã¨ã®ãã¨ã
person = '{ "name": "Alice", "children": [ { "name": "Bob", "age": 2 } ] }' case JSON.parse(person, symbolize_names: true) in {name: 'Alice', children: [{name: 'Bob', age: age}]} p age # => 2 end
ã·ã³ãã«ï¼ï¼
3. ä»æ§ã«ã¤ãã¦
Syntax
- æåã«ãããããã¾ã§å®è¡ããã
- ã©ã®ãã¿ã¼ã³ããããããªãå ´åã
else
ç¯ãå®è¡ããã - ã©ã®ãã¿ã¼ã³ãããããã
else
ç¯ããªãå ´åãNoMatchinPatternError
ãçºçããã
1ã¨2ã¯ç¾ç¶ã®caseã¨åãã§ããã
ã©ã®æ¡ä»¶ã«ãä¸è´ããªãå ´åã¯ä¾å¤ãçºçããã®ã§ããã¿ã¼ã³ãããã使ãæã«ã¯ç¶²ç¾
æ§ã確èªãã¦ãã ãããã¨ã®ãã¨ã§ããã
4.if/unless
ã§æ¡ä»¶ã¥ããã§ãã
case [0, 1] in [a, b] unless a == b p a # => 0 p b # => 1 end
a, bãå
ã«è©ä¾¡ããããããããæã«if/unless
ãè©ä¾¡ããã¾ãã
ãªã®ã§ããããããå¤ãå©ç¨ããè©ä¾¡ãå¯è½ããããï¼
Pattern
1. ValuePattern
case/when
ã¨åæ§ã«ã===
ã§è©ä¾¡ããã¾ãã
case 0 in 0 in -1..1 in Integer end
ã©ãã¨ãããããã¾ããwhen
ã¨åãæåã
2. VariablePettern
å
ç¨ã¾ã§ã®ä¾ã®ããã«å¤ããããããããã®å¤æ°ã¨å¤ãçµã³ä»ãããã¾ãã
ã¾ãã_
ã使ãã¨å¤ãæ¨ã¦ã¦ãã¯ã¤ã«ãã«ã¼ãçã«ä½¿ãã¾ãã
case [0, 1] in [_, _] :reachable end
注æç¹ã¨ãã¦ã¯ãin
ç¯ã§å¤æ°ã使ãã¨ãcase
å¥ã®å¤ã§å¤æ°ãå®ç¾©ãã¦ãã¦ããã¿ã¼ã³ãããããã¦ãã¾ããã¨ã
ãã¿ã¼ã³ãããã§ã¯ãªãå®ç¾©ãããå¤æ°ã¨ãã¦ä½¿ãããå ´åã¯^
ã使ãã¾ãã
a = 0 case 1 in a p a # => 1 end a = 0 case 1 in ^a :unreachable end # => NoMatchingPatternError
3. AlternativePattern
caseæãæ¸ãå§ãã¦ãã°ãããã¦ããããªæãã§æ¸ãããâ¦ã¨æã£ãè¨æ¶ãããã¾ãã
ç¾å®ã«ãªã£ãï¼ãããï¼
case 0 in 0 | 1 | 2 :reachable end
4. As
Pattern
ãã¿ã¼ã³ããããããæã=>
ã§å¤æ°åãæå®ãããã¨ã§å¤æ°ã¨å¤ãçµã³ä»ãããã¾ãã
ãã®ä½¿ãåæã®ããããããã
ValuePatternã ããããªãã¦ãä»ã®ãã¿ã¼ã³ã§ã使ãã¾ãã
case 0 in Integer => a p a # => 0 end case 0 in 0 | 1 | 2 => a p a # => 0 end case [0, [1, 2]] in [0, [1, _] => a] p a # => [1, 2] end
5. ArrayPattern
ArrayPatternã¨ã¯ããããã©ãArray以å¤ã§ã使ãã¾ãã
以ä¸ã®3ã¤ãæºããæã«ããããã¾ãã
- Constant === objectã®æ
- objectãArrayãè¿ãdeconstructã¡ã½ãããæã¤æ
- ãã¹ãããobjectã2ã®æ¡ä»¶ãæºããæ
ã¾ãããã¿ã¼ã³ã®æ¸ãæ¹ã¯ä¸è¨ã®ããããå¯è½ã§ãã
Constant(pattern, pattern, ..., *var, pattern)
Constant[pattern, pattern, ..., *var, pattern]
[pattern, pattern, ..., *var, pattern]
case [0, 1, 2] in Array(0, *a, 2) in Object[0, *a, 2] in [0, *a, 2] in 0, *a, 2 # `[]`ã¯çç¥ã§ãã end p a # => [1]
ãã®4ã¤ã¯å
¨ã¦åãçµæã
ãµã¨æ°ã«ãªã£ãã®ããin [0, *a, 2]
ã£ã¦æåã®ä¾ã¨åãã
deconstruct
ã¡ã½ããå®è£
ããªãã¦ããã®ï¼ã¨æã£ã¦ç¢ºèªãã¦ã¿ãã¨ã[].methods.include? :deconstruct # => true
ã§ããã
Ruby2.6.2ã§ã¯[].methods.size
ã188
ã2.7.0-devã§ã¯189
ã«ãªã£ã¦ãã¦ãããâ¦ã¨ãªãã¾ããã
ãã¦ãå
è¿°ããéããArrayPatternã¯Array以å¤ã§ã使ãã¾ãã
objectãArrayãè¿ãã°OKãªã®ã§ãå®è£
ãã¦ããã¾ãã
class Struct alias deconstruct to_a end Color = Struct.new(:r, :g, :b) color = Color[0, 10, 20] p color.deconstruct # => [0, 10, 20] case color in Color[0, 0, 0] p 'black' in Color[255, 0, 0] p 'red' in Color[r, g, b] p "#{r}, #{g}, #{b}" end
StructãArrayãè¿ããããdeconstruct
ãto_a
ã®ã¨ã¤ãªã¢ã¹ã«è¨å®ãã¦ãã¾ãã
ã¹ã©ã¤ãã«ã¯ASTã®ä¾ãããã¾ããããç解ã追ãã¤ããªãã®ã§ã¬ãã«ã¢ãããã¦ããåææ¦ãã¾ãã
6. HashPattern
HashPatternããHash以å¤ã§ã使ãã¾ãã
以ä¸ã®3ã¤ãæºããæã«ããããã¾ãã
- Constant === objectã®æ
- objectãHashãè¿ãdeconstruct_keysã¡ã½ãããæã¤æ
- ãã¹ãããobjectã2ã®æ¡ä»¶ãæºããæ
ã¾ãããã¿ã¼ã³ã®æ¸ãæ¹ãArrayåæ§ä¸è¨ã®ããããå¯è½ã§ãã
Constant(id: pattern, id: pattern, ..., **var) Constant[id: pattern, id: pattern, ..., **var] {id: pattern, id: pattern, ..., **var}
Arrayã«å¼ãç¶ã確èªããã¨ã{}.methods.include? :deconstruct_keys # => true
ã
ãã ãä»åã¯Ruby2.6.2ã§ã¯{}.methods.size
ã174
ã2.7.0-devã§ã¯176
ã
ã²ã¨ã¤ã¯deconstruct_keys
ã¨ãã¦ãããã²ã¨ã¤ã¯ï¼ã¨ç¢ºèªãã¦ã¿ãã¨ã:tally
ã§ããã
tally
ã¯é
åã®è¦ç´ æ°ãè¦ç´ æ¯ã«æ°ãä¸ããEnumerableã¢ã¸ã¥ã¼ã«ã®ã¡ã½ããã
ãã¡ãã楽ãã¿ã§ãð
ãã¦ãã³ã¼ããè¦ã¦ã¿ã¾ãã
case {a: 0, b: 1} in Hash(a: a, b: 1) p a # => 0 in Object[a: a] in {a: a} in {a: a, **rest} p rest # => {b: 1} end
{}
ã¯çç¥å¯ãå¤æ°åãçç¥ã§ãã¾ã(a:
== a: a
)ã
case {a: 0, b: 1} in a:, b: p a # => 0 p b # => 1 end
ã¾ããdeconstruct_keys
ã®å®è£
ã§æããããªãå¤ãè¿ãã¨éå¹æã«ãªãã®ã§ãå®è£
ã«æ³¨æãã¦ãã ããã¨ã®ãã¨ã§ããã
deconstruct_keys
ã«æ¸¡ãããkeys
ã¯ãã¿ã¼ã³ã«å«ã¾ããkey
ã®é åkeys
ã«å«ã¾ãã¦ããªãkey
ã¯ç¡è¦ãã¦OK**rest
ããã¿ã¼ã³ã«å«ã¾ããå ´åã¯nilã渡ã- ãã®å ´åãå ¨ã¦ã®key-valueã»ãããè¿ããªããã°ãªããªã
ã³ã¼ããè¦ãã»ãããããããããã§ãã
class Time VALID_KEYS = %i(year month) def deconstruct_keys(keys) if keys (VALID_KEYS & keys).each_with_object({}) do |k, h| h[k] = send(k) end else {year: year, month: month} end end end now = Time.now # 2019-05-07 ... case now in year: # now.deconstruct_keys([:year])ãå¼ã¶ p year # => {year: 2019} in **rest # now.deconstruct_keys(nil)ãå¼ã¶ p rest # => {year: 2019, month: 5} end
Arrayã¨Hashã®éãã§æ°ãã¤ãããã®ã¯ãArrayã¯å®å
¨ä¸è´ãHashã¯ãµãã»ããããããªãã¨ã
Arrayã¨Hashã§ã¯ä½¿ãæãéããããã¨ã®ãã¨ã§ããã
case [0, 1] in [a] :unreachable in [a, *] :reachable end case {a: 0, b: 1} in {a: a} :reachable end
ãã¶ã¤ã³
Historyã¯æéããªãã¦ã»ãã·ã§ã³ä¸ç«¯æããã¦ãã¾ã£ãã®ã§ãããã¹ã©ã¤ãã«ããã¨2012å¹´ã«gemãä½ã£ããã¨ãã端ãçºãã¦ã7å¹´ããã¦ä½ãããæ©è½ã
æåã¯match/pattern
ã ã£ããcase/=>
ã«ãªã£ã¦ãã£ãããæéãããã¦æ§ã
èãããã磨ãã¬ããã¦ãã£ãæ§ã«ãããããã¾ãï¼
ãã¼ã¯ã¼ãããmatch
ã§ãªãcase
ããã®ã¯ãmatch
ã ã¨æ¢åã®ã³ã¼ããå£ãã¦ãã¾ãå¯è½æ§ãããããã
æ°ããäºç´èªã使ããªãããã«æåã¯è¨å·ã使ã£ãããããã¨ãã¦ããã®ã ãã©ãããã ãåãã«ã¯for/in
ã®in
ããããããªããï¼ã¨æãã¤ãã話ãããã好ãã§ãã
ãªãã¹ãèªç¶ã«æ¸ããããã«ãã§ãæ¢åã®ã³ã¼ããå£ããªãããã«ã
ã³ã¼ãã試ãæ¸ããã¦ãã¦ä½åº¦ãæ°æã¡ãããªããã¨æã£ãã®ã§ãããRubyã®ãéçºè
ã楽ãããã£ã¦ãããã¦å®ãããä½ããã¦ãããã ãªããã¨æ¹ãã¦æãå
¥ãã¾ããã
ã¾ããã¾ã ãã£ã¨ããããããã ãã©ãã©ãæãï¼ã¨ããã¹ã©ã¤ãããããããã£ã¦ããããããã¾ããã
ãã¿ã¼ã³ãããã³ã°ã楽ãã¿ã§ãï¼