跳到内容

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}