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 表达式,可以把它省掉。 这样,每个 when 表达式都会按其真假值来求值。 它们的行为也就和 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
在这个练习中,我们将模拟一局 Blackjack 游戏的第一个回合。
你会拿到两张牌,并且能看到庄家亮出的那张牌。 所有牌都用字符串表示,比如 "ace"、"king"、"three"、"two" 等。 每张牌的点数如下:
| 牌 | 点数 | 牌 | 点数 |
|---|---|---|---|
| ace | 11 | eight | 8 |
| two | 2 | nine | 9 |
| three | 3 | ten | 10 |
| four | 4 | jack | 10 |
| five | 5 | queen | 10 |
| six | 6 | king | 10 |
| seven | 7 | other | 0 |
通常 ace 可以取 1 或 11 点,但为了简单起见,我们假设它只能取 11 点。
实现 Blackjack.parse_card 方法,它接收一张牌(字符串)作为参数。
该方法应返回这张牌的点数,类型为整数。
Blackjack.parse_card("ace")
# => 11
玩家得分需要划分到不同的分数区间。 玩家得分由两张手牌的点数相加得出。 使用的区间如下:
| 区间 | 分值 |
|---|---|
| low | [4, 11] |
| mid | [12, 16] |
| high | [17, 20] |
| blackjack | [21] |
实现 Blackjack.card_range 方法,它接收两张牌(字符串)作为参数。
该方法应返回这两张牌所属分数区间的名称。
Blackjack.card_range("ten", "king")
# => "high"
根据你的两张牌和庄家的牌,游戏第一个回合有一套策略,你可以选择以下操作:
虽然还不算最优,但你会采用朋友 Alex 一直在完善的策略,内容如下:
实现 Blackjack.first_turn 方法,它接收三张牌(字符串)作为参数。
该方法应返回你应采取的决策,类型为字符串。
Blackjack.first_turn("ace", "ace", "two")
# => "P"