if/elif/else表达式可以用来按条件执行逻辑。F# 还有一种更强大的条件执行方式:模式匹配。使用模式匹配时,可以把一个值和一个或多个_模式_进行匹配测试。其中一种模式是常量模式,它把一个值和常量进行匹配(例如1或"hello")。
在 F# 中,模式匹配通过match关键字完成:
let describe number =
match number with
| 0 -> "Zero"
| 1 -> "One"
这看起来和其他语言里的switch语句很像,但当你同时使用其他模式时,模式匹配才开始展现威力。其中一种模式是变量模式,它可以把一个值捕获下来:
match number with
| 0 -> "Zero"
| i -> sprintf "Non zero: %d" i
有时你可能想给模式再加一个条件。这称为_守卫_(子句),可以用when关键字来添加:
match number with
| 0 -> "Zero"
| i when i < 0 -> "Negative number"
守卫子句可以是任何有效的表达式,其中也包括调用函数。
在上面的例子里,并非所有可能的输入都有能匹配的模式。编译器会检测到这一点,并给出警告。这称为穷尽匹配。要消除这个警告,就必须处理所有情况。为此可以使用[通配符模式][wildcard-pattern],它能匹配任何值:
match number with
| i when i < 0 -> "Negative number"
| _ -> "Positive number"
// No compiler warning
注意,编译器无法借助when子句推断出匹配是否穷尽:
match number with
| i when i < 0 -> "Negative number"
| i when i >= 0 -> "Positive number"
// Compiler warning
模式匹配会自上而下地把值和每一个模式依次比较,直到找到匹配的模式,并执行与该模式关联的逻辑。模式的顺序很重要!因此,通配符模式应该始终是match表达式里的最后一个模式。
虽然模式匹配非常强大,但简单的条件逻辑通常用if/else表达式表达会更清晰:
let usingPatternMatching number =
match number with
| 0 -> "Zero"
| _ -> "Non-zero"
let usingIfElse number = if number = 0 then "Zero" else "Non-zero"