Match Expressions
Inspect one language lane at a time so line-level text and code deltas stay readable.
Diff Lane
English
0 modified sections0 code block delta0 anchor delta
Diff Lane
中文
2 modified sections0 code block delta0 anchor delta
modifiedmatch 表达式的定义text+1 line, -1 line
v1.0.5
Section Text
1
仓颉支持两种 `match` 表达式,第一种是包含待匹配值的 `match` 表达式,第二种是不含待匹配值的 `match` 表达式。2
3
**含匹配值的 match 表达式**:4
5
<!-- verify -->6
7
8
`match` 表达式以关键字 `match` 开头,后跟要匹配的值,如上例中的 `x`,`x` 可以是任意表达式。接着是定义在一对花括号内的若干 `case` 分支,每个 `case` 分支以关键字 `case` 开头,`case` 之后是一个模式或多个由 `|` 连接的相同种类的模式,上例中的 `1`、`0`、`_` 均为模式,详见[模式概述](../enum_and_pattern_match/pattern_overview.md)章节。后面紧跟 `=>`,`=>` 之后即本条 `case` 分支匹配成功后需要执行的操作,可以是一系列表达式、变量和函数定义。其中,新定义的变量或函数的作用域从其定义处开始到下一个 `case` 之前结束,如上例中的变量定义和 `print` 函数调用。9
10
上例中,因为 `x` 的值等于 `0`,所以会和第二条 `case` 分支匹配(此处使用的是常量模式,匹配的是值是否相等,详见[常量模式](../enum_and_pattern_match/pattern_overview.md#常量模式)章节),最后输出 `x = 0`。11
12
编译并执行上述代码,输出结果为:13
14
15
`match` 表达式要求所有匹配必须是穷尽(exhaustive)的,意味着待匹配表达式的所有可能取值都应该被考虑到。当 `match` 表达式非穷尽,或者编译器判断不出是否穷尽时,均会编译报错,换言之,所有 `case` 分支(包含 pattern guard)所覆盖的取值范围的并集,应该包含待匹配表达式的所有可能取值。常用的确保 `match` 表达式穷尽的方式是在最后一个 `case` 分支中使用通配符模式 `_`,因为 `_` 可以匹配任何值。16
17
`match` 表达式的穷尽性保证了一定存在和待匹配值相匹配的 `case` 分支。下面的例子将编译报错,因为所有的 `case` 并没有覆盖 `x` 的所有可能取值:18
19
<!-- compile.error -->20
21
22
如果被匹配值的类型包含 `enum` 类型且该 `enum` 为 `non-exhaustive enum`,则其在匹配时需要使用可匹配所有构造器的模式,如通配符模式 `_` 和绑定模式。23
24
<!-- compile -->25
26
27
在 `case` 分支的模式之后,可以使用 `pattern guard`(模式守卫)进一步对匹配出来的结果进行判断,此为可选内容。28
29
- `pattern guard` 表示本条 `case` 匹配成功后额外需要满足的条件,其使用 `where cond`(语法格式) 表示,要求表达式 `cond` 的类型为 `Bool`。30
31
`match` 表达式执行时,会依次将 `match` 之后的表达式与每个 `case` 中的模式进行匹配。如果有 `pattern guard`,需要 `where` 之后的表达式的值为 `true`;如果 `case` 中有多个由 `|` 连接的模式,只要待匹配值和其中一个模式匹配则认为匹配成功。一旦匹配成功,将执行 `=>` 之后的代码,然后退出 `match` 表达式的执行,这意味着不会再去匹配它之后的 `case`。如果匹配不成功,会继续与它之后的 `case` 中的模式进行匹配,直到匹配成功。`match` 表达式可以保证一定存在匹配的 `case` 分支。32
33
在下面的例子中,使用到了 `enum` 模式,详见 [enum 模式](../enum_and_pattern_match/pattern_overview.md#enum-模式)章节。当 `RGBColor` 的构造器的参数值大于等于 `0` 时,输出它们的值;当参数值小于 `0` 时,即满足第一个 `case` 的 `where cond`,则认为它们的值等于 `0`:34
35
<!-- verify -->36
37
38
编译执行上述代码,输出结果为:39
40
41
**没有匹配值的 match 表达式**:42
43
<!-- verify -->44
45
46
与包含待匹配值的 `match` 表达式相比,关键字 `match` 之后并没有待匹配的表达式,并且 `case` 之后不再是 `pattern`,而是类型为 `Bool` 的表达式(上述代码中的 `x > 0` 和 `x < 0`)或者 `_`(表示 `true`),当然,`case` 中也不再有 `pattern guard`。47
48
无匹配值的 `match` 表达式执行时依次判断 `case` 之后的表达式的值,直到遇到值为 `true` 的 `case` 分支;一旦某个 `case` 之后的表达式值等于 `true`,则执行此 `case` 中 `=>` 之后的代码,然后退出 `match` 表达式的执行(意味着不会再去判断该 `case` 之后的其他 `case`)。49
50
上例中,因为 `x` 的值等于 `-1`,所以第二条 `case` 分支中的表达式(即 `x < 0`)的值等于 `true`,执行 `print("x < 0")`。51
52
编译并执行上述代码,输出结果为:Code 1 · cangjie
1
main() {2
let x = 03
match (x) {4
case 1 => let r1 = "x = 1"5
print(r1)6
case 0 => let r2 = "x = 0" // Matched.7
print(r2)8
case _ => let r3 = "x != 1 and x != 0"9
print(r3)10
}11
}Code 2 · text
1
x = 0Code 3 · cangjie
1
func nonExhaustive(x: Int64) {2
match (x) {3
case 0 => print("x = 0")4
case 1 => print("x = 1")5
case 2 => print("x = 2")6
}7
}Code 4 · cangjie
1
enum T {2
| Red | Green | Blue | ...3
}4
func foo(a: T) {5
match (a) {6
case Red => 07
case Green => 18
case Blue => 29
case _ => -110
}11
}12
13
func bar(a: T) {14
match (a) {15
case Red => 016
case k => -1 // simple binding pattern17
}18
}19
20
func baz(a: T) {21
match (a) {22
case Red => 023
case k: T => -1 // binding pattern with nested type pattern24
}25
}Code 5 · cangjie
1
enum RGBColor {2
| Red(Int16) | Green(Int16) | Blue(Int16)3
}4
main() {5
let c = RGBColor.Green(-100)6
let cs = match (c) {7
case Red(r) where r < 0 => "Red = 0"8
case Red(r) => "Red = ${r}"9
case Green(g) where g < 0 => "Green = 0" // Matched.10
case Green(g) => "Green = ${g}"11
case Blue(b) where b < 0 => "Blue = 0"12
case Blue(b) => "Blue = ${b}"13
}14
print(cs)15
}Code 6 · text
1
Green = 0Code 7 · cangjie
1
main() {2
let x = -13
match {4
case x > 0 => print("x > 0")5
case x < 0 => print("x < 0") // Matched.6
case _ => print("x = 0")7
}8
}Code 8 · text
1
x < 0v1.1.0
Section Text
1
仓颉支持两种 `match` 表达式,第一种是包含待匹配值的 `match` 表达式,第二种是不含待匹配值的 `match` 表达式。2
3
**含匹配值的 match 表达式**:4
5
<!-- verify -->6
7
8
`match` 表达式以关键字 `match` 开头,后跟要匹配的值,如上例中的 `x`,`x` 可以是任意表达式。接着是定义在一对花括号内的若干 `case` 分支,每个 `case` 分支以关键字 `case` 开头,`case` 之后是一个模式或多个由 `|` 连接的相同种类的模式,上例中的 `1`、`0`、`_` 均为模式,详见[模式概述](../enum_and_pattern_match/pattern_overview.md)章节。后面紧跟 `=>`,`=>` 之后即本条 `case` 分支匹配成功后需要执行的操作,可以是一系列表达式、变量和函数定义。其中,新定义的变量或函数的作用域从其定义处开始到下一个 `case` 之前结束,如上例中的变量定义和 `print` 函数调用。9
10
上例中,因为 `x` 的值等于 `0`,所以会和第二条 `case` 分支匹配(此处使用的是常量模式,匹配的是值是否相等,详见[常量模式](../enum_and_pattern_match/pattern_overview.md#常量模式)章节),最后输出 `x = 0`。11
12
编译并执行上述代码,输出结果为:13
14
15
`match` 表达式要求所有匹配必须是穷尽(exhaustive)的,意味着待匹配表达式的所有可能取值都应该被考虑到。当 `match` 表达式非穷尽,或者编译器判断不出是否穷尽时,均会编译报错,换言之,所有 `case` 分支(包含 pattern guard)所覆盖的取值范围的并集,应该包含待匹配表达式的所有可能取值。常用的确保 `match` 表达式穷尽的方式是在最后一个 `case` 分支中使用通配符模式 `_`,因为 `_` 可以匹配任何值。16
17
`match` 表达式的穷尽性保证了一定存在和待匹配值相匹配的 `case` 分支。下面的例子将编译报错,因为所有的 `case` 并没有覆盖 `x` 的所有可能取值:18
19
<!-- compile.error -->20
21
22
如果被匹配值的类型包含 `enum` 类型且该 `enum` 为 `non-exhaustive enum`,则其在匹配时需要使用可匹配所有构造器的模式,如通配符模式 `_` 和绑定模式。23
24
<!-- compile -->25
26
27
在 `case` 分支的模式之后,可以使用 `pattern guard`(模式守卫)进一步对匹配出来的结果进行判断,此为可选内容。28
29
`pattern guard` 表示本条 `case` 匹配成功后额外需要满足的条件,其使用 `where cond`(语法格式) 表示,要求表达式 `cond` 的类型为 `Bool`。30
31
`match` 表达式执行时,会依次将 `match` 之后的表达式与每个 `case` 中的模式进行匹配。如果有 `pattern guard`,需要 `where` 之后的表达式的值为 `true`;如果 `case` 中有多个由 `|` 连接的模式,只要待匹配值和其中一个模式匹配则认为匹配成功。一旦匹配成功,将执行 `=>` 之后的代码,然后退出 `match` 表达式的执行,这意味着不会再去匹配它之后的 `case`。如果匹配不成功,会继续与它之后的 `case` 中的模式进行匹配,直到匹配成功。`match` 表达式可以保证一定存在匹配的 `case` 分支。32
33
在下面的例子中,使用到了 `enum` 模式,详见 [enum 模式](../enum_and_pattern_match/pattern_overview.md#enum-模式)章节。当 `RGBColor` 的构造器的参数值大于等于 `0` 时,输出它们的值;当参数值小于 `0` 时,即满足第一个 `case` 的 `where cond`,则认为它们的值等于 `0`:34
35
<!-- verify -->36
37
38
编译执行上述代码,输出结果为:39
40
41
**没有匹配值的 match 表达式**:42
43
<!-- verify -->44
45
46
与包含待匹配值的 `match` 表达式相比,关键字 `match` 之后并没有待匹配的表达式,并且 `case` 之后不再是 `pattern`,而是类型为 `Bool` 的表达式(上述代码中的 `x > 0` 和 `x < 0`)或者 `_`(表示 `true`),当然,`case` 中也不再有 `pattern guard`。47
48
无匹配值的 `match` 表达式执行时依次判断 `case` 之后的表达式的值,直到遇到值为 `true` 的 `case` 分支;一旦某个 `case` 之后的表达式值等于 `true`,则执行此 `case` 中 `=>` 之后的代码,然后退出 `match` 表达式的执行(意味着不会再去判断该 `case` 之后的其他 `case`)。49
50
上例中,因为 `x` 的值等于 `-1`,所以第二条 `case` 分支中的表达式(即 `x < 0`)的值等于 `true`,执行 `print("x < 0")`。51
52
编译并执行上述代码,输出结果为:Code 1 · cangjie
1
main() {2
let x = 03
match (x) {4
case 1 => let r1 = "x = 1"5
print(r1)6
case 0 => let r2 = "x = 0" // Matched.7
print(r2)8
case _ => let r3 = "x != 1 and x != 0"9
print(r3)10
}11
}Code 2 · text
1
x = 0Code 3 · cangjie
1
func nonExhaustive(x: Int64) {2
match (x) {3
case 0 => print("x = 0")4
case 1 => print("x = 1")5
case 2 => print("x = 2")6
}7
}Code 4 · cangjie
1
enum T {2
| Red | Green | Blue | ...3
}4
func foo(a: T) {5
match (a) {6
case Red => 07
case Green => 18
case Blue => 29
case _ => -110
}11
}12
13
func bar(a: T) {14
match (a) {15
case Red => 016
case k => -1 // simple binding pattern17
}18
}19
20
func baz(a: T) {21
match (a) {22
case Red => 023
case k: T => -1 // binding pattern with nested type pattern24
}25
}Code 5 · cangjie
1
enum RGBColor {2
| Red(Int16) | Green(Int16) | Blue(Int16)3
}4
main() {5
let c = RGBColor.Green(-100)6
let cs = match (c) {7
case Red(r) where r < 0 => "Red = 0"8
case Red(r) => "Red = ${r}"9
case Green(g) where g < 0 => "Green = 0" // Matched.10
case Green(g) => "Green = ${g}"11
case Blue(b) where b < 0 => "Blue = 0"12
case Blue(b) => "Blue = ${b}"13
}14
print(cs)15
}Code 6 · text
1
Green = 0Code 7 · cangjie
1
main() {2
let x = -13
match {4
case x > 0 => print("x > 0")5
case x < 0 => print("x < 0") // Matched.6
case _ => print("x = 0")7
}8
}Code 8 · text
1
x < 0modifiedmatch 表达式的类型text+2 lines, -2 lines
v1.0.5
Section Text
1
对于 `match` 表达式(无论是否有匹配值):2
3
- 在上下文有明确的类型要求时,要求每个 `case` 分支中 `=>` 之后的代码块的类型是上下文所要求的类型的子类型;4
5
- 在上下文没有明确的类型要求时,`match` 表达式的类型是每个 `case` 分支中 `=>` 之后的代码块的类型的最小公共父类型;6
7
- 当 `match` 表达式的值没有被使用时,其类型为 `Unit`,不要求各分支的类型有最小公共父类型。8
9
下面分别举例说明。10
11
<!-- compile -->12
13
14
上面的例子中,定义变量 `s` 时,显式地标注了其类型为 `String`,属于上下文类型信息明确的情况,因此要求每个 `case` 的 `=>` 之后的代码块的类型均是 `String` 的子类型,显然上例中 `=>` 之后的字符串类型的字面量均满足要求。15
16
再来看一个没有上下文类型信息的例子:17
18
<!-- compile -->19
20
21
上例中,定义变量 `s` 时,未显式标注其类型,因为每个 `case` 的 `=>` 之后的代码块的类型均是 `String`,所以 `match` 表达式的类型是 `String`,进而可确定 `s` 的类型也是 `String`。Code 1 · cangjie
1
let x = 22
let s: String = match (x) {3
case 0 => "x = 0"4
case 1 => "x = 1"5
case _ => "x != 0 and x != 1" // Matched.6
}Code 2 · cangjie
1
let x = 22
let s = match (x) {3
case 0 => "x = 0"4
case 1 => "x = 1"5
case _ => "x != 0 and x != 1" // Matched.6
}v1.1.0
Section Text
1
对于 `match` 表达式(无论是否有匹配值):2
3
- 在上下文有明确的类型要求时,要求每个 `case` 分支中 `=>` 之后的代码块的类型是上下文所要求的类型的子类型。4
5
- 在上下文没有明确的类型要求时,`match` 表达式的类型是每个 `case` 分支中 `=>` 之后的代码块的类型的最小公共父类型。6
7
- 当 `match` 表达式的值没有被使用时,其类型为 `Unit`,不要求各分支的类型有最小公共父类型。8
9
下面分别举例说明。10
11
<!-- compile -->12
13
14
上面的例子中,定义变量 `s` 时,显式地标注了其类型为 `String`,属于上下文类型信息明确的情况,因此要求每个 `case` 的 `=>` 之后的代码块的类型均是 `String` 的子类型,显然上例中 `=>` 之后的字符串类型的字面量均满足要求。15
16
再来看一个没有上下文类型信息的例子:17
18
<!-- compile -->19
20
21
上例中,定义变量 `s` 时,未显式标注其类型,因为每个 `case` 的 `=>` 之后的代码块的类型均是 `String`,所以 `match` 表达式的类型是 `String`,进而可确定 `s` 的类型也是 `String`。Code 1 · cangjie
1
let x = 22
let s: String = match (x) {3
case 0 => "x = 0"4
case 1 => "x = 1"5
case _ => "x != 0 and x != 1" // Matched.6
}Code 2 · cangjie
1
let x = 22
let s = match (x) {3
case 0 => "x = 0"4
case 1 => "x = 1"5
case _ => "x != 0 and x != 1" // Matched.6
}