跳到主要內容

invalid_case_patterns

實驗性
有可用修復

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

詳情

#

在庫升級到 3.0 時,一些在 Dart 2.19 及更早版本中有效的 case 表示式將成為錯誤或語義發生變化。此 lint 標記這些表示式,以便簡化遷移到 Dart 3.0 的過程。

在 Dart 3.0 中,一些在 2.19 中有效的 switch case 將成為編譯錯誤

  • 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'}: ...
}

目前,只有當傳入值與常量具有相同的 identity 時,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 當前只有當傳入值具有相同的 identity 時才會匹配。使用模式時,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

如果您正在使用 YAML map 語法配置 linter 規則,請在 linter > rules 下新增 invalid_case_patterns: true

analysis_options.yaml
yaml
linter:
  rules:
    invalid_case_patterns: true