内容

invalid_case_patterns

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

此规则目前处于实验性阶段,从 Dart 3.0 开始可用。

此规则提供了一个快速修复

详情

#

在 Dart 2.19 及以下版本中有效的某些 case 表达式,在库升级到 3.0 后将成为错误或语义发生变化。此 lint 会标记这些表达式,以便于迁移到 Dart 3.0。

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

  • 集合字面量
  • 带括号的表达式
  • 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 在语法上也是有效的模式,但模式匹配行为可能与当前的常量相等性行为不同。它们是

列表和映射字面量。列表或映射字面量可以作为 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".
}

使用模式时,列表或映射字面量将成为列表或映射模式。该模式会解构传入的对象,并在所有子模式都匹配时进行匹配。换句话说,列表和映射模式使用类似于深度相等性的东西进行匹配。

使用 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”,因为没有布尔值可以同时为真和假。

许多无效情况可以通过机械方式更改为在当今 Dart 中有效且在 Dart 3.0 中有效且含义相同的内容。

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

列表字面量、映射字面量、集合字面量和常量构造函数调用:在字面量或调用之前放置 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