Pular para o conteúdo principal

Desvios

Aprenda a usar desvios para controlar o fluxo do seu código Dart.

Esta página mostra como você pode controlar o fluxo do seu código Dart usando desvios:

  • Instruções e elementos if
  • Instruções e elementos if-case
  • Instruções e expressões switch

Você também pode manipular o fluxo de controle em Dart usando:

If

#

O Dart suporta instruções if com cláusulas else opcionais. A condição entre parênteses após if deve ser uma expressão que avalia para um boolean:

dart
if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}

Para aprender como usar if em um contexto de expressão, confira Expressões condicionais.

If-case

#

As instruções if do Dart suportam cláusulas case seguidas de um pattern:

dart
if (pair case [int x, int y]) return Point(x, y);

Se o pattern corresponder ao valor, o desvio é executado com as variáveis que o pattern define no escopo.

No exemplo anterior, o list pattern [int x, int y] corresponde ao valor pair, então o desvio return Point(x, y) é executado com as variáveis que o pattern definiu, x e y.

Caso contrário, o fluxo de controle segue para o desvio else, para ser executado, se houver um:

dart
if (pair case [int x, int y]) {
  print('Was coordinate array $x,$y');
} else {
  throw FormatException('Invalid coordinates.');
}

A instrução if-case oferece uma forma de fazer match e desestruturar contra um único pattern. Para testar um valor contra vários patterns, use switch.

Instruções switch

#

Uma instrução switch avalia uma expressão de valor contra uma série de cases. Cada cláusula case é um pattern para o valor comparar. Você pode usar qualquer tipo de pattern em um case.

Quando o valor corresponde ao pattern de um case, o corpo do case é executado. Cláusulas case não vazias pulam para o fim do switch após a conclusão. Elas não exigem uma instrução break. Outras formas válidas de encerrar uma cláusula case não vazia são uma instrução continue, throw ou return.

Use uma cláusula default ou o wildcard _ para executar código quando nenhuma cláusula case corresponder:

dart
var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
  case 'PENDING':
    executePending();
  case 'APPROVED':
    executeApproved();
  case 'DENIED':
    executeDenied();
  case 'OPEN':
    executeOpen();
  default:
    executeUnknown();
}

Cases vazios passam para o próximo case, permitindo que cases compartilhem um corpo. Para um case vazio que não passa adiante, use break para o corpo dele. Para passagem não sequencial, você pode usar uma instrução continue e um label:

dart
switch (command) {
  case 'OPEN':
    executeOpen();
    continue newCase; // Continues executing at the newCase label.
​
  case 'DENIED': // Empty case falls through.
  case 'CLOSED':
    executeClosed(); // Runs for both DENIED and CLOSED,
​
  newCase:
  case 'PENDING':
    executeNowClosed(); // Runs for both OPEN and PENDING.
}

Você pode usar logical-or patterns para permitir que cases compartilhem um corpo ou um guard. Para aprender mais sobre patterns e cláusulas case, confira a documentação de patterns sobre Switch statements and expressions.

Expressões switch

#

Uma expressão switch produz um valor com base no corpo da expressão do case que corresponder. Você pode usar uma expressão switch onde quer que o Dart permita expressões, exceto no início de uma instrução de expressão. Por exemplo:

dart
var x = switch (y) { ... };
​
print(switch (x) { ... });
​
return switch (x) { ... };

Se você quiser usar um switch no início de uma instrução de expressão, use uma instrução switch.

Expressões switch permitem reescrever uma instrução switch assim:

dart
// Where slash, star, comma, semicolon, etc., are constant variables...
switch (charCode) {
  case slash || star || plus || minus: // Logical-or pattern
    token = operator(charCode);
  case comma || semicolon: // Logical-or pattern
    token = punctuation(charCode);
  case >= digit0 && <= digit9: // Relational and logical-and patterns
    token = number();
  default:
    throw FormatException('Invalid');
}

Em uma expressão, assim:

dart
token = switch (charCode) {
  slash || star || plus || minus => operator(charCode),
  comma || semicolon => punctuation(charCode),
  >= digit0 && <= digit9 => number(),
  _ => throw FormatException('Invalid'),
};

A sintaxe de uma expressão switch difere da sintaxe da instrução switch:

  • Cases não começam com a keyword case.
  • O corpo de um case é uma única expressão, em vez de uma série de instruções.
  • Cada case deve ter um corpo; não há passagem implícita para cases vazios.
  • Os patterns dos cases são separados de seus corpos usando => em vez de :.
  • Cases são separados por , (e uma , final opcional é permitida).
  • Cases default podem usar apenas _, em vez de permitir tanto default quanto _.

Verificação de exaustividade

#

A verificação de exaustividade é um recurso que relata um erro de tempo de compilação se for possível que um valor entre em um switch sem corresponder a nenhum dos cases.

dart
// Non-exhaustive switch on bool?, missing case to match null possibility:
switch (nullableBool) {
  case true:
    print('yes');
  case false:
    print('no');
}

Um case default (default ou _) cobre todos os valores possíveis que podem passar por um switch. Isso torna um switch sobre qualquer tipo exaustivo.

Enums e tipos sealed são especialmente úteis para switches porque, mesmo sem um case default, seus valores possíveis são conhecidos e totalmente enumeráveis. Use o modificador sealed em uma classe para habilitar a verificação de exaustividade ao fazer switch sobre subtipos dessa classe:

dart
sealed class Shape {}
​
class Square implements Shape {
  final double length;
  Square(this.length);
}
​
class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}
​
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => math.pi * r * r,
};

Se alguém adicionar uma nova subclasse de Shape, esta expressão switch ficaria incompleta. A verificação de exaustividade avisaria você sobre o subtipo faltante. Isso permite usar Dart de um jeito um tanto funcional, no estilo de tipos de dados algébricos.

Cláusula guard

#

Para definir uma cláusula guard opcional após uma cláusula case, use a keyword when. Uma cláusula guard pode seguir if case, e tanto instruções quanto expressões switch.

dart
// Switch statement:
switch (something) {
  case somePattern when some || boolean || expression:
    //             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause.
    body;
}
​
// Switch expression:
var value = switch (something) {
  somePattern when some || boolean || expression => body,
  //               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause.
}
​
// If-case statement:
if (something case somePattern when some || boolean || expression) {
  //                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause.
  body;
}

Guards avaliam uma expressão booleana arbitrária depois do matching. Isso permite adicionar restrições extras sobre se o corpo de um case deve ser executado. Quando a cláusula guard avalia para false, a execução segue para o próximo case, em vez de sair de todo o switch.

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