模式匹配
模式的种类
- 通配模式(_)
- 常量模式
- 变量模式
- 构造方法模式
- 序列模式
- 元组模式
- 带类型的模式
变量绑定@
- 除了独自存在的变量模式,我们还可以对任何其他模式添加变量。只需要写下变量名、一个@符号和模式本身,就可以得到一个变量绑定模式,这意味着这个模式将像平常一样执行模式匹配。如果匹配成功,就将匹配的对象赋值给这个变量,就像简单的变量模式一样。
模式守卫
- 模式守卫出现在模式之后,并以if开头。模式守卫可以是任意的布尔表达式,通常会引用模式中的变量。如果存在模式守卫,则这个匹配仅在模式守卫求值得到true时才会成功。因此,上面提到的首个case只能匹配那些两个操作元相等的二元操作。
模式重叠
模式会按照代码中的顺序逐个被尝试。示例13.15中的simplifyAll展示了模式中的case出现顺序的重要性。
示例13.15中的simplifyAll将会对一个表达式中的各部分都执行简化,不像simplifyTop那样仅仅在顶层做简化。simplifyAll可以从simplifyTop演化出来,只需要再添加两个分别针对一元和二元表达式的case即可(示例13.15中的第四个和第五个case)。
第四个case的模式是UnOp(op,e),它匹配所有的一元操作。这个一元操作的操作符和操作元可以是任意的。它们分别被绑定到模式变量op和e上。这个case对应的可选分支会递归地对操作元e应用simplifyAll,然后用(可能的)简化后的操作元重建这个一元操作。第五个BinOp的case也同理:它是一个“捕获所有”(catch-all)的对任意二元操作的匹配,并在匹配成功后递归地对它的两个操作元应用简化方法。
在本例中,捕获所有的case出现在更具体的简化规则之后,这是很重要的。如果我们将顺序颠倒过来,则捕获所有的case就会优先于更具体的简化规则执行。在许多场景下,编译器甚至会拒绝编译。例如,下面这个match表达式就无法通过编译,因为首个case将会匹配所有第二个case能匹配的值: