case¶
case
は、パターンマッチングに少し似た機能を持つ制御式です。セマンティクスを少し変更し、さらに強力な構造を持つif-else-ifの連鎖を記述できます。
基本形では、ある値を他の値と比較できます
case exp
when value1, value2
do_something
when value3
do_something_else
else
do_another_thing
end
# The above is the same as:
tmp = exp
if value1 === tmp || value2 === tmp
do_something
elsif value3 === tmp
do_something_else
else
do_another_thing
end
式をcase
の対象と比較するために、コンパイラはケース包含演算子 ===
を使用します。これはObject
のメソッドとして定義されており、サブクラスによってオーバーライドして、case文で意味のあるセマンティクスを提供できます。たとえば、Class
は、オブジェクトがそのクラスのインスタンスである場合にケース包含を定義し、Regex
は値が正規表現に一致する場合、Range
は値がその範囲に含まれる場合に定義します。
when
の式が型である場合、is_a?
が使用されます。さらに、case式が変数または変数代入である場合、変数の型が制限されます。
case var
when String
# var : String
do_something
when Int32
# var : Int32
do_something_else
else
# here var is neither a String nor an Int32
do_another_thing
end
# The above is the same as:
if var.is_a?(String)
do_something
elsif var.is_a?(Int32)
do_something_else
else
do_another_thing
end
暗黙のオブジェクト構文を使用すると、when
内でcase
式のメソッドを呼び出すことができます。
case num
when .even?
do_something
when .odd?
do_something_else
end
# The above is the same as:
tmp = num
if tmp.even?
do_something
elsif tmp.odd?
do_something_else
end
when
条件の後でthen
を使用して、本文を1行に配置できます。
case exp
when value1, value2 then do_something
when value3 then do_something_else
else do_another_thing
end
最後に、case
の値を省略できます。
case
when cond1, cond2
do_something
when cond3
do_something_else
end
# The above is the same as:
if cond1 || cond2
do_something
elsif cond3
do_something_else
end
これにより、場合によってはより自然に読めるコードになることがあります。
タプルリテラル¶
case式がタプルリテラルである場合、when
条件もタプルリテラルである場合、いくつかのセマンティックな違いがあります。
タプルのサイズは一致する必要がある¶
case {value1, value2}
when {0, 0} # OK, 2 elements
# ...
when {1, 2, 3} # Syntax error: wrong number of tuple elements (given 3, expected 2)
# ...
end
アンダースコアが許可される¶
case {value1, value2}
when {0, _}
# Matches if 0 === value1, no test done against value2
when {_, 0}
# Matches if 0 === value2, no test done against value1
end
暗黙のオブジェクトが許可される¶
case {value1, value2}
when {.even?, .odd?}
# Matches if value1.even? && value2.odd?
end
型との比較は is_a? チェックを実行する¶
case {value1, value2}
when {String, Int32}
# Matches if value1.is_a?(String) && value2.is_a?(Int32)
# The type of value1 is known to be a String by the compiler,
# and the type of value2 is known to be an Int32
end
網羅的なcase¶
when
の代わりにin
を使用すると、網羅的なcase式が生成されます。網羅的なcaseでは、必要なin
条件のいずれかを省略するとコンパイル時エラーになります。網羅的なcase
にwhen
またはelse
句を含めることはできません。
コンパイラは、次のin
条件をサポートしています。
共用体型のチェック¶
case
の式が共用体の値である場合、共用体の各型を条件として使用できます。
# var : (Bool | Char | String)?
case var
in String
# var : String
in Char
# var : Char
in Bool
# var : Bool
in nil # or Nil, but .nil? is not allowed
# var : Nil
end
Bool値¶
case
の式がBool
値の場合、true
とfalse
のリテラルを条件として使用できます。
# var : Bool
case var
in true
do_something
in false
do_something_else
end
Enum値¶
case
の式がフラグではないEnum値の場合、そのメンバーを定数または述語メソッドとして条件として使用できます。
enum Foo
X
Y
Z
end
# var : Foo
case var
in Foo::X
# var == Foo::X
in .y?
# var == Foo::Y
in .z? # :z is not allowed
# var == Foo::Z
end
タプルリテラル¶
条件は、case
式の要素の可能なすべての組み合わせを網羅する必要があります
# value1, value2 : Bool
case {value1, value2}
in {true, _}
# value1 is true, value2 can be true or false
do_something
in {_, false}
# here value1 is false, and value2 is also false
do_something_else
end
# Error: case is not exhaustive.
#
# Missing cases:
# - {false, true}