Fluxo de controle de ramificações

I. Ramificações básicas if / if-else

  1. A expressão dentro dos parênteses do if deve ser sempre booleana; conversão implícita para tipo booleano não é permitida.
  2. Vários blocos else if podem ser encadeados, com um bloco else opcional no final.
  3. Chaves podem ser omitidas se houver apenas uma linha de código, mas recomenda-se usá-las todas as vezes para melhor legibilidade.
void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Levar capa de chuva");
  } else if (isSnowing) {
    print("Vestir casaco grosso");
  } else {
    print("Dirigir conversível");
  }
}Code language: Dart (dart)

Resultado da execução

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Vestir casaco grossoCode language: CSS (css)

Também é possível usar o if isoladamente

void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Levar capa de chuva");
  }
}Code language: Dart (dart)

Ou apenas um if else

void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Levar capa de chuva");
  } else {
    print("Dirigir conversível");
  }
}Code language: Dart (dart)

II. Ramificação de casamento de padrão if-case (Dart 3.0+)

  1. Quando o padrão combinar, as variáveis são desestruturadas e vinculadas ao escopo atual.
  2. Se o casamento falhar, o código pula para o else. Você pode adicionar um guard when para validações booleanas extras.
  3. Destinado ao casamento de um valor com um único padrão; utilize switch quando precisar lidar com vários padrões.
void main() {
  final pair = [100, 220];
  // Casa com uma lista contendo dois números inteiros
  if (pair case [int x, int y]) {
    print("Coordenada: $x,$y");
  } else {
    throw FormatException("Coordenada inválida");
  }
}Code language: Dart (dart)

Resultado da execução

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Coordenada: 10,20Code language: CSS (css)

2: if-case combinado com guard when

void main() {
  final data = [8, 9];
  if (data case [int a, int b] when a > 5 && b > 5) {
    print("Os dois números são maiores que 5");
  } else {
    print("Os números não atendem à condição");
  }
}Code language: Dart (dart)

Resultado da execução

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Os dois números são maiores que 5Code language: CSS (css)

III. Comando switch

Switch tradicional no formato de comando, sem valor de retorno

  1. Cases aceitam todos os tipos de padrões: strings, constantes, OU lógico, padrões relacionais
  2. Cases com conteúdo saem automaticamente com break, não é necessário escrever break manualmente; cases vazios causam fallthrough implícito.
  3. Duas formas de forçar fallthrough manual: continue rótulo ou encadear casos vazios
  4. O bloco default executa quando nenhum case combinar; compatível com guards when
1: Casamento básico de string
void main() {
  String command = "OPEN";
  switch (command) {
    case "CLOSED":
      print("Executar lógica de fechamento");
    case "PENDING":
      print("Executar lógica de espera");
    case "OPEN":
      print("Executar lógica de abertura");
    default:
      print("Comando desconhecido");
  }
}
Code language: Dart (dart)

Resultado da execução

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Executar lógica de aberturaCode language: CSS (css)

2: Fallthrough com case vazio + salto via continue rótulo

String command = "OPEN";
switch (command) {
  case "OPEN":
    print("Operação de abertura"); // ① Combina com OPEN e executa a impressão
    continue newCase; // ② Salta diretamente para o rótulo newCase, não retorna

  case "DENIED": 
  case "CLOSED":
    print("Operação de fechamento");

  newCase: // ③ Destino do salto
  case "PENDING":
    print("Lógica unificada para processos pendentes"); // ④ Executado sem verificar command == "PENDING"
}Code language: Dart (dart)

Resultado da execução

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Operação de abertura
Lógica unificada para processos pendentesCode language: CSS (css)

Neste exemplo, continue newCase; salta para o rótulo newCase, mas o case seguinte “PENDING” não combina, por que o código print("Lógica unificada para processos pendentes"); mesmo assim roda?

Essa é uma dúvida recorrente dos leitores

continue rótulo; não reavalia o valor testado, salta direto para o início do bloco case marcado pelo rótulo, ignora todas as validações de condição e executa o código do bloco imediatamente.

3: switch com guard when

void main() {
  int score = 88;
  switch (score) {
    case int s when s >= 90:
      print("Excelente");
    case int s when s >= 60:
      print("Aprovado");
    default:
      print("Reprovado");
  }
}
Code language: Dart (dart)

Saída: Aprovado

Primeiro valida o tipo: o valor precisa ser inteiro. Se for, atribui à variável s. Depois o guard when faz uma segunda validação; o código do case só roda se s atender à condição do when. As duas declarações int s têm escopos independentes e não interferem uma na outra.

Cada case int s é uma vinculação de padrão independente, cujo escopo é restrito apenas ao seu próprio bloco case.

Você pode usar nomes de variáveis diferentes sem alterar o funcionamento do código.

switch (score) {
  case int a when a >= 90:
    print("Excelente");
  case int b when b >= 60:
    print("Aprovado");
  default:
    print("Reprovado");
}Code language: Dart (dart)

IV. Expressão switch

Sintaxe liberada a partir do Dart 3.0, possui valor de retorno e é amplamente utilizada para atribuição de variáveis

Diferenças em relação ao comando switch

  1. Não existe a palavra-chave case; o símbolo => separa o padrão e a expressão de retorno
  2. Cada ramificação deve retornar uma expressão, as ramificações são separadas por vírgulas
  3. Não há fallthrough implícito, cada ramificação é independente. Quando nenhum padrão combinar, use o sublinhado _ ao invés de default
  4. Pode ser usado diretamente em atribuições, chamadas print, return e qualquer contexto de expressão

1: Casamento básico de operadores de caractere (padrão OU lógico)

void main() {
  const slash = 47, star = 42, comma = 44;
  int charCode = 42;

  final token = switch (charCode) {
    slash || star => "Operador",
    comma => "Pontuação",
    _ => "Caractere inválido"
  };
  print(token);
}
Code language: Dart (dart)

Resultado da execução

Operador

Esse exemplo define constantes com os códigos ASCII de três símbolos e classifica o caractere da variável charCode como operador, pontuação ou símbolo inválido.

2: Expressão switch com guard when

void main() {
  int age = 22;
  String level = switch (age) {
    int a when a < 18 => "Menor de idade",
    int a when a < 30 => "Jovem adulto",
    _ => "Adulto"
  };
  print(level);
}Code language: Dart (dart)

Resultado da execução

Jovem adulto

3: Uso direto da expressão switch no retorno de função

void main() {
  print(getDesc(3));
}

String getDesc(int num) => switch (num) {
  1 => "Um",
  2 => "Dois",
  _ => "Outro número"
};
Code language: Dart (dart)

Resultado da execução

Outro número

Observação: Aqui o switch é uma expressão e getDesc é uma função de seta. Funções de seta são uma sintaxe exclusiva do Dart que não existe em outras linguagens da família C.

V. Verificação de exaustividade (Exhaustiveness Checking)

Erro em tempo de compilação se faltarem cases para valores de entrada possíveis; o compilador obriga a completar todos os casos. Classes sealed e enums suportam verificação exaustiva nativamente sem necessidade de _ ou default.

1: Erro de falta de exaustividade em booleano anulável (comente/descomente para visualizar o erro)

void main() {
  bool? nullableBool = null;
  // Descomentar o código abaixo causa erro de compilação: falta case para null e não há fallback com _/default
  /*
  switch (nullableBool) {
    case true:
      print("Verdadeiro");
    case false:
      print("Falso");
  }
  */
  // Correção: adicionar case null ou fallback com _
  switch (nullableBool) {
    case true:
      print("Verdadeiro");
    case false:
      print("Falso");
    case null:
      print("Valor nulo");
  }
}Code language: PHP (php)

Resultado da execução

Valor nulo

2: Classe sealed (selada)

Tipo de dado algébrico que força o casamento completo de padrões

import 'dart:math' as math;

// Classe sealed: subclasses só podem ser definidas neste arquivo
sealed class Shape {}

// Subclasse Quadrado: comprimento do lado
class Square implements Shape {
  final double length;
  Square(this.length);
}

//Subclasse Círculo: raio
class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

// Função de seta que calcula a área via casamento switch no objeto de subclasse recebido
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => math.pi * r * r
  // Adicionar nova subclasse de Shape gera erro de compilação por falta de case
};

void main() {
  final Shape circle = Circle(5);
  print(calculateArea(circle));
  final Shape square = Square(4);
  print(calculateArea(square));
}
Code language: Dart (dart)

Resultado da execução

78.53981633974483
16.0Code language: CSS (css)

3: Casamento exaustivo com enum

Não é necessário o sublinhado de fallback _

void main() {
  final Animal animal = Animal.cat;
  String name = switch (animal) {
    Animal.dog => "Cachorro",
    Animal.cat => "Gato"
  };
  print(name);
}

enum Animal { dog, cat }
Code language: Dart (dart)

Saída: Gato

Enums possuem um conjunto finito e fixo de valores, então não é preciso criar ramificação de fallback.

VI. Guards when

Suportados em if-case, comandos switch e expressões switch

Função do when: executar validação booleana extra após o casamento bem-sucedido do padrão. Se o guard retornar false, segue para a próxima ramificação sem sair do switch.

1. if-case + when

void main() {
  List<int> arr = [10, 20];
  if (arr case [int x, int y] when x + y > 20) {
    print("A soma dos dois números é maior que 20");
  }
}Code language: Dart (dart)
A soma dos dois números é maior que 20

Primeiro verifica se é uma lista com dois inteiros; se o padrão combinar, o when checa se a soma ultrapassa 20.

2. Comando switch + when

void main() {
  int num = 15;
  switch(num) {
    case int n when n % 2 == 0:
      print("Número par");
    case int n when n % 2 != 0:
      print("Número ímpar");
  }
}
Code language: PHP (php)

Saída: Número ímpar

Primeiro confirma que o tipo é inteiro, depois valida a condição dentro do when.

3. Expressão switch + when

void main() {
  int num = 15;
  String res = switch(num) {
    int n when n % 2 == 0 => "Número par",
    _ => "Número ímpar"
  };
  print(res);
}
Code language: PHP (php)

Fluxo de controle de ramificações

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *