Pular para o conteúdo principal

invalid_case_patterns

Saiba mais sobre a regra de lint invalid_case_patterns.

Experimental
Correção disponível
Lançado no Dart 3.0

Use expressões case válidas no Dart 3.0.

Detalhes

#

Algumas expressões case que são válidas no Dart 2.19 e anteriores passarão a gerar erro ou terão a semântica alterada quando uma biblioteca for atualizada para o Dart 3.0. Esta lint sinaliza essas expressões para facilitar a migração para o Dart 3.0.

Algumas cases de switch válidas no 2.19 passarão a ser erros de compilação no Dart 3.0:

  • Literais de conjunto
  • Expressões entre parênteses
  • Chamadas a identical().
  • Expressões com operadores unários !, - ou ~ (exceto - antes de um literal inteiro, que é um padrão válido e está tudo bem)
  • Expressões com operadores binários !=, ==, &, |, ^, ~/, >>, >>>, <<, +, -, *, /, %, <, <=, >, >=, ??.
  • Operador condicional ?:
  • Chamadas .length em strings
  • Expressões is e is!

Exemplos de todos eles:

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.
}

Algumas cases de switch válidas no 2.19 também são padrões sintaticamente válidos, mas o comportamento de pattern matching pode ser diferente do comportamento atual de igualdade de constantes. São elas:

Literais de lista e de mapa. Um literal de lista ou de mapa pode aparecer como constante em um case:

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

Atualmente, o case só dará match se o valor recebido tiver a mesma identidade da constante. Assim:

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".
}

Com padrões, um literal de lista ou de mapa se torna um padrão de lista ou de mapa. O padrão desestrutura o objeto recebido e dá match se todos os subpadrões derem match. Em outras palavras, o match de padrões de lista e de mapa usa algo mais parecido com igualdade profunda.

Com o Dart 3.0, o programa acima imprime "Matched" duas vezes.

Chamadas de construtor constante. De forma semelhante às coleções, você pode construir uma instância constante de uma classe em um 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".
}

Novamente, como nas coleções, o case atualmente só dá match se o valor recebido tiver a mesma identidade. Com padrões, a sintaxe Point(...) se torna um padrão de objeto que desestrutura o ponto recebido, chama os getters x e y nele e então compara os resultados com os subpadrões correspondentes.

Neste exemplo, ele imprimirá "Matched" duas vezes.

Observe que padrões de objeto suportam apenas campos nomeados. Assim, qualquer construtor constante usado em um case hoje com argumentos posicionais se tornará um erro de compilação quando for interpretado como padrão. Uma chamada de construtor constante sem argumentos é um padrão de objeto válido e faz apenas um teste de tipo:

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".
}

Quando interpretado como padrão, isso imprime "Matched" duas vezes.

Curingas. Hoje, você pode ter uma constante chamada _:

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".
}

Com padrões, o identificador _ é tratado como um padrão que dá match em todos os valores, então isso imprime "Matched" duas vezes.

Operadores lógicos. Os operadores lógicos && e || são expressões constantes válidas e também padrões válidos. Como expressão constante, eles simplesmente avaliam a expressão para um booleano e dão match se o valor recebido for igual a esse valor booleano. Assim:

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".
}

Com o Dart 3.0, eles se tornam padrões. O exemplo acima imprime "Did not match" duas vezes, porque nenhum valor booleano pode ser verdadeiro e falso ao mesmo tempo.

Muitos dos casos inválidos podem ser alterados mecanicamente para algo que é válido tanto no Dart atual quanto no Dart 3.0, e que tem o mesmo significado.

Expressões entre parênteses: desde que a expressão interna não seja uma que quebre no Dart 3.0, basta remover os parênteses.

Literais de lista, literais de mapa, literais de conjunto e chamadas de construtor constante: coloque const antes do literal ou da chamada. Isso o transforma em um padrão constante, o que preserva o comportamento atual:

RUIM:

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

BOM:

dart
case const [1, 2]:
case const {'k': 'v'}:
case const {1, 2}:
case const Point(1, 2):
  • Curingas: renomeie a constante de _ para outro nome. Como o nome é privado, isso pode ser feito localmente na biblioteca, sem afetar outro código.

  • Todo o resto: para qualquer outra expressão inválida, é preciso extrair a expressão para uma nova constante nomeada. Por exemplo, se você tiver um código como este:

RUIM:

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

Pode ser corrigido alterando para:

BOM:

dart
const three = 1 + 2;
​
switch (n) {
 case three: ...
}

Ativar

#

Para ativar a regra invalid_case_patterns, adicione invalid_case_patterns em linter > rules no seu arquivo analysis_options.yaml:

analysis_options.yaml
yaml
linter:
  rules:
    - invalid_case_patterns

Se você usa a sintaxe de mapa YAML para configurar as regras de lint, adicione invalid_case_patterns: true em linter > rules:

analysis_options.yaml
yaml
linter:
  rules:
    invalid_case_patterns: true

Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.