やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

「Ruby プログラムの実行」を読む3(パターンマッチ case-when, case-in)

 C言語switch文より高機能。

成果物

情報源

case-when

case [式]
[when 式 [, 式] ...[, '*' 式] [then]
  式..]..
[when '*' 式 [then]
  式..]..
[else
  式..]
end

 以下caseは以下ifと等価である。when===であり,or

case0
when1, 式2
  stmt1
when3, 式4
  stmt2
else
  stmt3
end
_tmp = 式0
if1 === _tmp or2 === _tmp
  stmt1
elsif3 === _tmp or4 === _tmp
  stmt2
else
  stmt3
end
case 7
when 1,3,5,7,9
  '奇数'
when 0,2,4,6,8
  '偶数'
else
  '範囲外'
end

 以下のように,|にすると範囲外になってしまった。

case 7
when 1|3|5|7|9
  '奇数'
when 0|2|4|6|8
  '偶数'
else
  '範囲外'
end

 when句の値は配列展開したものを渡せる。以下は等価。

ary = [1,2,3]
case v
when *ary
 ..
end
case v
when 1, 2, 3
 ..
end

 ..で範囲チェックできる。以下は等価。

$age = 10
case $age
when 0 .. 2
  "baby"
when 3 .. 6
  "little child"
when 7 .. 12
  "child"
when 13 .. 18
  "youth"
else
  "adult"
end
$age = 10
case $age
when Range.new(0, 2)
  "baby"
when Range.new(3, 6)
  "little child"
when Range.new(7, 12)
  "child"
when Range.new(13, 18)
  "youth"
else
  "adult"
end
$age = 10
if 0 <= $age and $age <= 2
  "baby"
elsif 3 <= $age and $age <= 6
  "little child"
elsif 7 <= $age and $age <= 12
  "child"
elsif 13 <= $age and $age <= 18
  "youth"
else
  "adult"
end

case-in(パターンマッチ)

 Ruby2.7.0から追加された。Feature#14912, pattern-matching-new-feature参照。3.0.0でさらに追加/変更あり。pattern_matching_rdoc参照。

 構文は以下のとおり。

casein パターン [if|unless 条件式]
  式
[...]
[else
  式]
end

 詳細は以下。

case expr
in pat [if|unless cond]
  ...
in pat [if|unless cond]
  ...
else
  ...
end

pat: var                                                   # Variable pattern. It matches any value, and binds the variable name to that value.
   | literal                                               # Value pattern. The pattern matches an object such that pattern === object.
   | Constant                                              # Ditto.
   | var_                                                  # Ditto. It is equivalent to pin operator in Elixir.
   | (pat, ..., *var, pat, ..., id:, id: pat, ..., **var)  # Deconstructing pattern. See below for more details.
   | pat(pat, ...)                                         # Ditto. Syntactic sugar of (pat, pat, ...).
   | pat, ...                                              # Ditto. You can omit the parenthesis (top-level only). 
   | pat | pat | ...                                       # Alternative pattern. The pattern matches if any of pats match.
   | pat => var                                            # As pattern. Bind the variable to the value if pat match.

# one-liner version
$(pat, ...) = expr                                         # Deconstructing pattern.

 これまでのcase-when式と同じようにパターンには値もセットできる。===比較する。

$age = 10
case $age
in 0 .. 2
  "baby"
in 3 .. 6
  "little child"
in 7 .. 12
  "child"
in 13 .. 18
  "youth"
else
  "adult"
end

 これまでのcase-when式と同じようにパターンにはOR判定できる。ただしセパレータは,でなく|である。

case 7
in 1|3|5|7|9
  '奇数'
in 0|2|4|6|8
  '偶数'
else
  '範囲外'
end
=> 奇数

 以下のように|,にすると範囲外になってしまった。

case 7
in 1,3,5,7,9
  '奇数'
in 0,2,4,6,8
  '偶数'
else
  '範囲外'
end
=> 範囲外

 ほかにもたくさん記法がある。パターンマッチについては別途勉強したほうが良さそう。

所感

 パターンマッチcase-inの記法が超むずかしそう。執筆時点ではまだ新しい記法らしく変更も入っているようだ。有用だが勉強は後回しにしてもいいだろう。

対象環境