已开启
docs(match): describe sealed match exhaustiveness #577
Cangjie-Sundaiyue创建于 8月12日
docs(match): describe sealed match exhaustiveness #577
已开启
共 2 个文件变更+52-0
| @@ -37,6 +37,32 @@ x = 0 | |||
| 37 | 37 | ||
| 38 | The `match` expression requires that all matches must be exhaustive, meaning all possible values of the expression to be matched should be considered. When the `match` expression is not exhaustive, or the compiler cannot determine whether it is exhaustive, a compilation error will occur. In other words, the union of the value ranges covered by all `case` branches (including pattern guards) should include all possible values of the expression to be matched. A common way to ensure the exhaustiveness of the `match` expression is to use the wildcard pattern `_` in the last `case` branch, as `_` can match any value. | 38 | The `match` expression requires that all matches must be exhaustive, meaning all possible values of the expression to be matched should be considered. When the `match` expression is not exhaustive, or the compiler cannot determine whether it is exhaustive, a compilation error will occur. In other words, the union of the value ranges covered by all `case` branches (including pattern guards) should include all possible values of the expression to be matched. A common way to ensure the exhaustiveness of the `match` expression is to use the wildcard pattern `_` in the last `case` branch, as `_` can match any value. |
| 39 | 39 | ||
| 40 | +### Exhaustive Matching of Sealed Types | ||
| 41 | + | ||
| 42 | +For a `sealed abstract class` or `sealed interface` whose definition and `match` expression are in the current package, the final wildcard pattern `_` can be omitted when the type patterns in the `case` branches list every possible subtype. For example: | ||
| 43 | + | ||
| 44 | +<!-- compile --> | ||
| 45 | + | ||
| 46 | +```cangjie | ||
| 47 | +sealed interface Color {} | ||
| 48 | + | ||
| 49 | +class Red <: Color {} | ||
| 50 | +class Green <: Color {} | ||
| 51 | +class Blue <: Color {} | ||
| 52 | + | ||
| 53 | +func describe(color: Color): String { | ||
| 54 | + match (color) { | ||
| 55 | + case _: Red => "red" | ||
| 56 | + case _: Green => "green" | ||
| 57 | + case _: Blue => "blue" | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | +``` | ||
| 61 | + | ||
| 62 | +Here, `Color` and its subtypes are in the current package, and none of the three subtypes can be inherited further, so the type patterns cover every possible `Color` value. A trailing `_` is unnecessary; if it is added, the compiler reports an `unreachable pattern` warning. | ||
| 63 | + | ||
| 64 | +Keep `_` when the compiler cannot determine that the set of subtypes is closed. For example, this is the case when the `sealed` type is imported from another package, a subtype is declared `private` in another source file and cannot be named at the matching location, or a subtype can be inherited further, such as an `open`, `abstract`, or `sealed` subtype or a child interface. The same rule applies to nested type patterns in tuples and in arguments of enum constructors. | ||
| 65 | + | ||
| 40 | The exhaustiveness of the `match` expression ensures that there must be a `case` branch that matches the value to be matched. The following example will result in a compilation error because not all possible values of `x` are covered by the `case` branches: | 66 | The exhaustiveness of the `match` expression ensures that there must be a `case` branch that matches the value to be matched. The following example will result in a compilation error because not all possible values of `x` are covered by the `case` branches: |
| 41 | 67 | ||
| 42 | <!-- compile.error --> | 68 | <!-- compile.error --> |
| @@ -37,6 +37,32 @@ x = 0 | |||
| 37 | 37 | ||
| 38 | `match` 表达式要求所有匹配必须是穷尽(exhaustive)的,意味着待匹配表达式的所有可能取值都应该被考虑到。当 `match` 表达式非穷尽,或者编译器判断不出是否穷尽时,均会编译报错,换言之,所有 `case` 分支(包含 pattern guard)所覆盖的取值范围的并集,应该包含待匹配表达式的所有可能取值。常用的确保 `match` 表达式穷尽的方式是在最后一个 `case` 分支中使用通配符模式 `_`,因为 `_` 可以匹配任何值。 | 38 | `match` 表达式要求所有匹配必须是穷尽(exhaustive)的,意味着待匹配表达式的所有可能取值都应该被考虑到。当 `match` 表达式非穷尽,或者编译器判断不出是否穷尽时,均会编译报错,换言之,所有 `case` 分支(包含 pattern guard)所覆盖的取值范围的并集,应该包含待匹配表达式的所有可能取值。常用的确保 `match` 表达式穷尽的方式是在最后一个 `case` 分支中使用通配符模式 `_`,因为 `_` 可以匹配任何值。 |
| 39 | 39 | ||
| 40 | +### sealed 类型的穷尽匹配 | ||
| 41 | + | ||
| 42 | +对于定义和匹配都位于当前包中的 `sealed abstract class` 或 `sealed interface`,如果 `case` 中的类型模式已经列出了所有可能的子类型,则可以省略最后的通配符模式 `_`。例如: | ||
| 43 | + | ||
| 44 | +<!-- compile --> | ||
| 45 | + | ||
| 46 | +```cangjie | ||
| 47 | +sealed interface Color {} | ||
| 48 | + | ||
| 49 | +class Red <: Color {} | ||
| 50 | +class Green <: Color {} | ||
| 51 | +class Blue <: Color {} | ||
| 52 | + | ||
| 53 | +func describe(color: Color): String { | ||
| 54 | + match (color) { | ||
| 55 | + case _: Red => "red" | ||
| 56 | + case _: Green => "green" | ||
| 57 | + case _: Blue => "blue" | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | +``` | ||
| 61 | + | ||
| 62 | +这里的 `Color` 及其子类型均在当前包中,且三个子类型都不能继续被继承,因此这些类型模式已经覆盖 `Color` 的所有可能取值。末尾不需要再添加 `_`;若添加该分支,编译器会提示该模式不可达。 | ||
| 63 | + | ||
| 64 | +当编译器无法确定子类型集合是否封闭时,仍需保留 `_`。例如,`sealed` 类型从其他包导入、子类型在其他源文件中以 `private` 声明而无法在当前匹配位置命名,或者某个子类型仍可继续被继承(如 `open`、`abstract`、`sealed` 子类型或子接口)时,均应使用 `_` 作为兜底。该规则同样适用于元组中以及有参 `enum` 构造器参数中的嵌套类型模式。 | ||
| 65 | + | ||
| 40 | `match` 表达式的穷尽性保证了一定存在和待匹配值相匹配的 `case` 分支。下面的例子将编译报错,因为所有的 `case` 并没有覆盖 `x` 的所有可能取值: | 66 | `match` 表达式的穷尽性保证了一定存在和待匹配值相匹配的 `case` 分支。下面的例子将编译报错,因为所有的 `case` 并没有覆盖 `x` 的所有可能取值: |
| 41 | 67 | ||
| 42 | <!-- compile.error --> | 68 | <!-- compile.error --> |