メインコンテンツにスキップ

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呼び出し
  • isおよびis!

すべて例

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は、構文的にも有効なパターンですが、パターンマッチングの動作は現在の定数等価性の動作とは異なる場合があります。それらは以下の通りです。

リストとマップのリテラル。リストまたはマップのリテラルは、case内の定数として表示できます。

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

現在、caseは、受信した値が定数と同じIDを持っている場合にのみ一致します。したがって、

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では、上記のプログラムは2回「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は現在、受信した値が同じIDを持っている場合にのみ一致します。パターンを使用すると、Point(...)構文は受信したポイントを分解し、それに対してxおよびyゲッターを呼び出し、それらの結果を対応するサブパターンと一致させるオブジェクトパターンになります。

この例では、「Matched」と2回表示されます。

オブジェクトパターンは名前付きフィールドのみをサポートすることに注意してください。したがって、現在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".
}

パターンとして解釈すると、これは2回「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".
}

パターンを使用すると、識別子_はすべての値を一致させるパターンとして扱われるため、これは2回「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では、これらはパターンになります。上記の例は、真でも偽でもないブール値は存在しないため、2回「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

代わりにYAMLマップ構文を使用してlinterルールを構成している場合は、linter > rulesの下にinvalid_case_patterns: trueを追加してください。

analysis_options.yaml
yaml
linter:
  rules:
    invalid_case_patterns: true