內容

invalid_case_patterns

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

此規則目前為實驗性,並於 Dart 3.0 開始提供。

此規則提供快速修正

詳細資訊

#

在 Dart 2.19 及更早版本中有效的某些 case 表達式,當函式庫升級到 3.0 時會變成錯誤或語意已變更。此程式碼檢查器會標記這些表達式,以便簡化遷移到 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 在語法上也是有效的模式,但模式比對行為可能與目前的常數相等行為不同。它們是

清單和 Map 字面值。 清單或 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".
}

使用模式,清單或 Map 字面值會變成清單或 Map 模式。該模式會解構傳入的物件,並在子模式全部比對時進行比對。換句話說,清單和 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 中沒有被破壞,只需捨棄括號即可。

清單字面值、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