case(在其他语言中通常称为 switch)是一种类似 if-else 的控制表达式。case可以把多个 if-else-if 语句串联起来,可读性更好,还能实现一些强大的构造。
case由关键字case定义,后面可以跟一个可选的表达式。之后每个分支都用关键字when引出,后面跟一个与 case 表达式比较的表达式。when关键字不应该比case关键字缩进得更深。when关键字后面是当 case 表达式与 when 表达式匹配时应该执行的代码。case 还允许一个可选的else语句,在没有其他分支匹配时执行。
先对 case 表达式求值,然后依次与每个 when 表达式比较。比较时使用的是case 包含运算符(===)。
case 1
when 1
puts "One"
when 2
puts "Two"
else
puts "Other"
end
# => One
# This is the same as:
tmp = 1
if 1 === tmp
puts "One"
elsif 2 === tmp
puts "Two"
else
puts "Other"
end
===)case 包含运算符(===)与相等运算符(==)有些不同。它检查的是右侧是不是左侧所描述的集合中的成员。也就是说,两个操作数放在哪一侧是有讲究的。具体行为取决于左侧的类型,例如Range会检查右侧是否落在该区间内,而Object会检查右侧是不是Object的实例。
(1..3) == 1 # => false
(1..3) === 1 # => true
String == "foo" # => false
String === "foo" # => true
case 可以在一个分支中匹配多个表达式,各个可能的值用逗号分隔。只要其中任意一个表达式匹配,就会执行对应的代码。当一个分支有多种可能的取值时,这会很有用。
case 1
when 1, 2
puts "One or two"
else
puts "Other"
end
case 还可以检查某个值是否落在区间内。做法是把区间作为 when 表达式。
case var
when 1..3
puts "One to three"
else
puts "Other"
end
如果不需要 case 表达式,可以把它省略。这样一来,每个分支的表达式都会按真假来求值,行为就像 if-else-if 语句一样。
case
when 1 == 1
puts "One is equal to one"
when 1 > 2
puts "One is greater than two"
else
puts "Other"
end
Crystal 允许使用单行的 case 语句。当分支只有一句简单的语句时,就可以这样写。单行的 when 语句写作 when <expression> then <statement>.。用在 else 分支时,写作 else <statement>。
case var
when 1 then puts "One"
when 2 then puts "Two"
else puts "Other"
end
case 还支持按类型匹配。比较时会用is_a?运算符检查变量的类型。例如,这样可以让联合类型中的每个类型各占一个分支。
case var
when Int32
puts "Int32"
when String
puts "String"
else
puts "Other"
end
case 支持使用隐式对象。这样一来,when 表达式就可以是对 case 表达式的方法调用。根据该方法返回的是真值还是假值,决定这个分支是否匹配。
case 1
when .odd?
puts "Odd"
when .even?
puts "Even"
end
case 支持穷尽式匹配,也就是说可以确保所有可能的取值都被处理到。它和 when 语句类似,只是用in关键字代替when。穷尽式 case 不支持任何when或else语句。
穷尽式 case 可用于Bools、Union类型、Enum和Tuples。后两者会在后面的概念中介绍。
穷尽式 case 意味着所有可能性都必须处理,否则会引发编译错误。把Union类型当作穷尽式 case 处理,与普通的非穷尽式 case 类似。
var : (Int32 | String | Bool)
case var
in Int32
puts "Int32"
in String
puts "String"
in Bool
puts "Bool"
end
用true和false关键字可以把Bools当作穷尽式 case 处理。
var : Bool
case var
in true
puts "True"
in false
puts "False"
end