33-模式匹配
模式匹配主要是通过关键字 match匹配到合适的值,再去执行对应的内容。语法层面可以理解为很多编程语言中的switch-case
模式匹配的分类
基于要匹配的数据类型不同,可以分成以下几种分类:
- 常量模式
- 通配符模式
- 绑定模式
- Tuple 模式
- 类型模式
- enum 模式
- 模式的嵌套组合
常量模式
常量模式可以是整数字面量、浮点数字面量、字符字面量、布尔字面量、字符串字面量(不支持字符串插值)、Unit 字面量。
数字匹配
|
表示可以连接多个模式
javascript
main() {
let score = 90
let level = match (score) {
case 0 | 10 | 20 | 30 | 40 | 50 => "D"
case 60 => "C"
case 70 | 80 => "B"
case 90 | 100 => "A" // Matched.
case _ => "Not a valid score"
}
println(level)
}
字符匹配
在模式匹配的目标是静态类型为 Rune
的值时,Rune
字面量和单字符字符串字面量都可用于表示 Rune
类型字面量的常量pattern
javascript
func translate(n: Rune) {
match (n) {
case "A" => 1
case "B" => 2
case "C" => 3
case _ => -1
}
}
main() {
println(translate(r"C"))
}
Byte匹配
一个表示 ASCII 字符的字符串字面量可用于表示 Byte
类型字面量的常量 pattern
javascript
func translate(n: Byte) {
match (n) {
case "1" => 1
case "2" => 2
case "3" => 3
case _ => -1 // 通配符模式
}
}
main() {
println(translate(51)) // UInt32(r'3') == 51
}
通配符模式
_
表示通配符模式,当上述所有的条件都不匹配时,便会匹配到通配符 _
javascript
func translate(n: Byte) {
match (n) {
case "1" => 1
case "2" => 2
case "3" => 3
case _ => -1
}
}
main() {
println(translate(51)) // UInt32(r'3') == 51
}
绑定模式
绑定模式类似通配符模式,区别是可以把当前符合条件的变量绑定到某个变量上。
绑定模式使用 id
表示,id
是一个合法的标识符。
id
不是具体的名称,理解是一占位符即可。实际上可以通过各种变量名来表示 id
也可以使用多个,不过只能是第一个会匹配到。
javascript
main() {
let x = -10
let y = match (x) {
case 0 => "zero"
case n => "x is not zero and x = ${n}" // Matched. n 表示 id
}
println(y)
}
需要注意的是,绑定模式不能和 |
连接多个模式共用,也不可嵌套出现在其它模式中
javascript
main() {
let opt = Some(0)
match (opt) {
case x | x => {} // Error, variable cannot be introduced in patterns connected by '|'
case Some(x) | Some(x) => {} // Error, variable cannot be introduced in patterns connected by '|'
case x: Int64 | x: String => {} // Error, variable cannot be introduced in patterns connected by '|'
}
}
Tuple 模式
Tuple 模式用于 tuple 值的匹配
javascript
main() {
let tv = ("Alice", 24)
let s = match (tv) {
case ("Bob", age) => "Bob is ${age} years old"
case ("Alice", age) => "Alice is ${age} years old" // Matched, "Alice" is a constant pattern, and 'age' is a variable pattern.
case (name, 100) => "${name} is 100 years old"
case (_, _) => "someone"
}
println(s)
}
类型模式
类型模式用于判断一个值的运行时类型是否是某个类型的子类型。类型模式有两种形式:_: Type
(嵌套一个通配符模式 _
)和 id: Type
(嵌套一个绑定模式 id
),它们的差别是后者会发生变量绑定,而前者并不会
javascript
open class Base {
var a: Int64
public init() {
a = 10
}
}
class Derived <: Base {
public init() {
a = 20
}
}
main() {
var d = Derived()
var r = match (d) {
case b: Base => b.a // Matched.
case _ => 0
}
println("r = ${r}")
}
enum 模式
enum 模式用于匹配 enum
类型的实例
javascript
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
main() {
let x = Year(2)
let s = match (x) {
case Year(n) => "x has ${n * 12} months" // Matched.
case TimeUnit.Month(n) => "x has ${n} months"
}
println(s)
}
使用 |
连接多个 enum 模式:
javascript
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
main() {
let x = Year(2)
let s = match (x) {
case Year(0) | Year(1) | Month(_) => "Ok" // Ok
case Year(2) | Month(m) => "invalid" // Error, Variable cannot be introduced in patterns connected by '|'
case Year(n: UInt64) | Month(n: UInt64) => "invalid" // Error, Variable cannot be introduced in patterns connected by '|'
}
println(s)
}
使用 match
表达式匹配 enum
值时,要求 case
之后的模式要覆盖待匹配 enum
类型中的所有构造器,如果未做到完全覆盖,
编译器将报错:
javascript
enum RGBColor {
| Red | Green | Blue
}
main() {
let c = Green
let cs = match (c) { // Error, Not all constructors of RGBColor are covered.
case Red => "Red"
case Green => "Green"
}
println(cs)
}
模式的嵌套组合
Tuple 模式和 enum 模式可以嵌套任意模式。
javascript
enum TimeUnit {
| Year(UInt64)
| Month(UInt64)
}
enum Command {
| SetTimeUnit(TimeUnit)
| GetTimeUnit
| Quit
}
main() {
let command = SetTimeUnit(Year(2022))
match (command) {
case SetTimeUnit(Year(year)) => println("Set year ${year}")
case SetTimeUnit(Month(month)) => println("Set month ${month}")
case _ => ()
}
}