跳至內容

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 的主體,編譯器使用 case 從屬運算子 ===。它被定義為 Object 的一個方法,並且可以被子類覆寫,以便在 case 語句中提供有意義的語義。例如,Class 將 case 從屬定義為當物件是該類別的實例時,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,將程式碼主體放在單行上。

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

使用 in 而不是 when 會產生一個窮舉 case 表達式;在窮舉 case 中,省略任何必要的 in 條件是一個編譯時錯誤。窮舉 case 不能包含任何 whenelse 子句。

編譯器支援下列 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

布林值

如果 case 的表達式是一個 Bool 值,則可以使用 truefalse 字面值作為條件

# var : Bool
case var
in true
  do_something
in false
  do_something_else
end

列舉值

如果 case 的表達式是一個非標誌列舉值,則其成員可以用作條件,可以是常數或謂詞方法。

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}