跳到主要内容

invalid_case_patterns

实验性
修复可用

使用在 Dart 3.0 中有效的 case 表达式。

详情

#

当库升级到 3.0 时,某些在 Dart 2.19 及更低版本中有效的 case 表达式将变成错误或具有更改的语义。此 lint 标记这些表达式,以便简化迁移到 Dart 3.0。

Dart 2.19 中某些有效的 switch case 在 Dart 3.0 中将变成编译错误

  • Set 字面量
  • 带括号的表达式
  • 调用 identical()
  • 一元运算符表达式 !-~(除了整数文字之前的 -,这是一个有效的模式,没有问题)
  • 二元运算符表达式 !===&|^~/>>>>><<+-*/%<<=>>=??
  • 条件运算符 ?:
  • 字符串上的 .length 调用
  • isis! 表达式

它们的所有示例

dart
switch (obj) {
  case {1}: // Set literal.
  case (1): // Parenthesized expression.
  case identical(1, 2): // `identical()` call.
  case -pi: // Unary operator.
  case 1 + 2: // Binary operator.
  case true ? 1 : 2: // Conditional operator.
  case 'hi'.length: // .length call.
  case i is int: // is expression.
}

Dart 2.19 中某些有效的 switch case 在语法上也是有效的模式,但模式匹配行为可能与当前的常量相等行为不同。它们是

List 和 Map 字面量。 List 或 Map 字面量可以作为 case 中的常量出现

dart
switch (obj) {
  case [1, 2]: ...
  case {'k': 'v'}: ...
}

目前,仅当传入值与常量具有相同的标识时,case 才会匹配。所以

dart
test(List<int> list) {
  switch (list) {
    case [1, 2]: print('Matched'); break;
    default: print('Did not match'); break;
  }
}

main() {
  test(const [1, 2]); // Prints "Matched".
  test([1, 2]); // Prints "Did not match".
}

使用模式,list 或 map 字面量会变成 list 或 map 模式。该模式解构传入的对象,并在子模式全部匹配时匹配。换句话说,list 和 map 模式匹配使用更类似于深层相等性的东西。

使用 Dart 3.0,上面的程序会打印 “Matched” 两次。

常量构造函数调用。 与集合类似,您可以在 case 中构造一个类的常量实例

dart
class Point {
  final int x;
  final int y;
  const Point({this.x, this.y});
}

test(Point p) {
  switch (p) {
    case Point(x: 1, y: 2): print('Matched'); break;
    default: print('Did not match'); break;
  }
}

main() {
  test(const Point(1, 2)); // Prints "Matched".
  test(Point(1, 2)); // Prints "Did not match".
}

同样,与集合类似,case 目前仅当传入值具有相同的标识时才匹配。使用模式,Point(...) 语法变成一个对象模式,该模式解构传入的点,在其上调用 xy getter,然后将这些结果与相应的子模式进行匹配。

在本例中,它将打印 “Matched” 两次。

请注意,对象模式仅支持命名字段。因此,今天 case 中任何具有位置参数的常量构造函数在解析为模式时都将变成编译时错误。没有参数的常量构造函数调用是有效的对象模式,并且仅执行类型测试

dart
class Thing {
  const Thing();
}

test(Thing t) {
  switch (t) {
    case Thing(): print('Matched'); break;
    default: print('Did not match'); break;
  }
}

main() {
  test(const Thing()); // Prints "Matched".
  test(Thing()); // Prints "Did not match".
}

当解释为模式时,这将打印 “Matched” 两次。

通配符。 今天,您可以有一个名为 _ 的常量

dart
test(int n) {
  const _ = 3;
  switch (n) {
    case _: print('Matched'); break;
    default: print('Did not match'); break;
  }
}

main() {
  test(3); // Prints "Matched".
  test(5); // Prints "Did not match".
}

使用模式,标识符 _ 被视为匹配所有值的模式,因此这将打印 “Matched” 两次。

逻辑运算符。 逻辑运算符 &&|| 是有效的常量表达式,也是有效的模式。作为常量表达式,它们只是将表达式求值为布尔值,并在传入值等于该布尔值时匹配。所以

dart
test(bool b) {
  switch (b) {
    case true && false: print('Matched'); break;
    default: print('Did not match'); break;
  }
}

main() {
  test(false); // Prints "Matched".
  test(true); // Prints "Did not match".
}

使用 Dart 3.0,这些变成模式。上面的示例打印 “Did not match” 两次,因为没有布尔值可以同时为 true 和 false。

许多无效的 case 可以机械地更改为在今天的 Dart 中有效,在 Dart 3.0 中也有效并且含义相同的内容。

带括号的表达式: 如果内部表达式在 Dart 3.0 中没有被破坏,只需丢弃括号。

List 字面量、Map 字面量、Set 字面量和常量构造函数调用: 在字面量或调用之前放置 const。这将其变成一个常量模式,从而保留当前行为

错误

dart
case [1, 2]:
case {'k': 'v'}:
case {1, 2}:
case Point(1, 2):

正确

dart
case const [1, 2]:
case const {'k': 'v'}:
case const {1, 2}:
case const Point(1, 2):
  • 通配符: 将常量从 _ 重命名为其他名称。由于该名称是私有的,因此可以在库本地完成此操作,而不会影响其他代码。

  • 其他所有内容: 对于任何其他无效表达式,您必须将表达式提升到一个新的命名常量中。例如,如果您有如下代码

错误

dart
switch (n) {
  case 1 + 2: ...
}

可以通过将其更改为

正确

dart
const three = 1 + 2;

switch (n) {
 case three: ...
}

启用

#

要启用 invalid_case_patterns 规则,请在您的 analysis_options.yaml 文件中的 linter > rules 下添加 invalid_case_patterns

analysis_options.yaml
yaml
linter:
  rules:
    - invalid_case_patterns

如果您改为使用 YAML 映射语法来配置 linter 规则,请在 linter > rules 下添加 invalid_case_patterns: true

analysis_options.yaml
yaml
linter:
  rules:
    invalid_case_patterns: true