跳到主要內容

invalid_case_patterns

實驗性
可修正

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

詳細資訊

#

某些在 Dart 2.19 及更早版本中有效的 case 表達式,當程式庫升級至 3.0 時,將會變成錯誤或語意有所變更。此 Lint 標記這些表達式,以方便遷移至 Dart 3.0。

某些在 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.
}

某些在 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。這會將其變成常數模式,從而保留目前的行為

BAD

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

GOOD

dart
case const [1, 2]:
case const {'k': 'v'}:
case const {1, 2}:
case const Point(1, 2):
  • 萬用字元: 將常數從 _ 重新命名為其他名稱。由於名稱是私有的,因此可以在程式庫中本地完成,而不會影響其他程式碼。

  • 其他所有內容: 對於任何其他無效的表達式,您必須將表達式提升到新的具名常數中。例如,如果您有像這樣的程式碼

BAD

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

可以透過將其變更為以下內容來修正

GOOD

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