Flujo de control por ramificaciones

I. Ramificaciones básicas if / if-else

  1. La expresión dentro de los paréntesis de if debe ser siempre booleana; no se permite la conversión implícita a tipo booleano.
  2. Se pueden encadenar varios bloques else if, con un bloque else opcional al final.
  3. Se pueden omitir las llaves si solo hay una línea de código, pero se recomienda usarlas siempre para mejorar la legibilidad.
void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Llevar impermeable");
  } else if (isSnowing) {
    print("Ponerse abrigo grueso");
  } else {
    print("Conducir descapotable");
  }
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Ponerse abrigo gruesoLenguaje del código: CSS (css)

También se puede usar if de forma independiente

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

  if (isRaining) {
    print("Llevar impermeable");
  }
}Lenguaje del código: Dart (dart)

O simplemente un if else

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

  if (isRaining) {
    print("Llevar impermeable");
  } else {
    print("Conducir descapotable");
  }
}Lenguaje del código: Dart (dart)

II. Ramificación de coincidencia de patrones if-case (Dart 3.0+)

  1. Si coincide el patrón, las variables se desestructuran y vinculan al ámbito actual.
  2. Si falla la coincidencia, salta a else. Se puede agregar un guardia when para comprobaciones booleanas adicionales.
  3. Diseñado para coincidencia de un valor y un solo patrón; usa switch si debes gestionar múltiples patrones.
void main() {
  final pair = [100, 220];
  // Coincide con una lista de dos números enteros
  if (pair case [int x, int y]) {
    print("Coordenadas: $x,$y");
  } else {
    throw FormatException("Coordenadas inválidas");
  }
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Coordenadas: 10,20Lenguaje del código: CSS (css)

2 : if-case combinado con guardia when

void main() {
  final data = [8, 9];
  if (data case [int a, int b] when a > 5 && b > 5) {
    print("Ambos números son mayores que 5");
  } else {
    print("Los números no cumplen la condición");
  }
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Ambos números son mayores que 5Lenguaje del código: CSS (css)

III. Instrucción switch

Switch tradicional en formato instrucción, sin valor de retorno

  1. Los casos aceptan todo tipo de patrones: cadenas, constantes, OR lógico, patrones relacionales
  2. Los casos con contenido terminan automáticamente con break, no hace falta escribir break manualmente; los casos vacíos generan caída implícita (fallthrough).
  3. Dos formas de forzar caída manual: continue etiqueta o encadenar casos vacíos
  4. Se ejecuta default cuando ningún caso coincide; compatible con guardias when
1 : Coincidencia básica de cadena
void main() {
  String command = "OPEN";
  switch (command) {
    case "CLOSED":
      print("Ejecutar lógica de cierre");
    case "PENDING":
      print("Ejecutar lógica de espera");
    case "OPEN":
      print("Ejecutar lógica de apertura");
    default:
      print("Comando desconocido");
  }
}
Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Ejecutar lógica de aperturaLenguaje del código: CSS (css)

2 : Caída de caso vacío + salto con continue y etiqueta

String command = "OPEN";
switch (command) {
  case "OPEN":
    print("Operación de apertura"); // ① Coincide con OPEN y ejecuta impresión
    continue newCase; // ② Salta directamente a la etiqueta newCase sin retroceder

  case "DENIED": 
  case "CLOSED":
    print("Operación de cierre");

  newCase: // ③ Destino del salto
  case "PENDING":
    print("Lógica unificada de procesos pendientes"); // ④ Se ejecuta sin comprobar command == "PENDING"
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Operación de apertura
Lógica unificada de procesos pendientesLenguaje del código: CSS (css)

En este ejemplo, continue newCase; salta hacia la etiqueta newCase, pero el siguiente case «PENDING» no coincide, ¿por qué se ejecuta igualmente print("Lógica unificada de procesos pendientes");?

Es una duda que tienen muchos lectores

continue etiqueta; no vuelve a comprobar el valor evaluado, salta directamente al inicio del bloque case marcado con la etiqueta, omite todas las comprobaciones de condición y ejecuta inmediatamente el código del bloque.

3 : switch combinado con guardia when

void main() {
  int score = 88;
  switch (score) {
    case int s when s >= 90:
      print("Excelente");
    case int s when s >= 60:
      print("Aprobado");
    default:
      print("Suspenso");
  }
}
Lenguaje del código: Dart (dart)

Salida: Aprobado

Primero se verifica el tipo: el valor debe ser entero. Si cumple, se asigna a s. Luego el guardia when realiza una segunda comprobación; el código del case solo se ejecuta si s cumple la condición del when. Las dos declaraciones int s tienen ámbitos independientes y no se interfieren entre sí.

Cada case int s es una vinculación de patrón independiente, cuyo ámbito se limita exclusivamente a su propio bloque case.

Puedes usar nombres de variables distintos sin modificar el comportamiento del programa.

switch (score) {
  case int a when a >= 90:
    print("Excelente");
  case int b when b >= 60:
    print("Aprobado");
  default:
    print("Suspenso");
}Lenguaje del código: Dart (dart)

IV. Expresión switch

Sintaxis disponible desde Dart 3.0, tiene valor de retorno y se usa frecuentemente para asignaciones

Diferencias con la instrucción switch

  1. No existe la palabra clave case; el símbolo => separa el patrón y la expresión de retorno
  2. Cada rama debe devolver una expresión, las ramas se separan con comas
  3. No hay caída implícita, cada rama es independiente. Si no coincide ningún patrón usa el guion bajo _ en lugar de default
  4. Se puede usar directamente en asignaciones, llamadas print, return y cualquier contexto de expresión

1 : Coincidencia básica de operadores de caracteres (patrón OR lógico)

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

  final token = switch (charCode) {
    slash || star => "Operador",
    comma => "Puntuación",
    _ => "Carácter inválido"
  };
  print(token);
}
Lenguaje del código: Dart (dart)

Resultado de ejecución

Operador

Este ejemplo define constantes con los códigos ASCII de tres símbolos y clasifica el carácter de la variable charCode como operador, puntuación o símbolo inválido.

2 : Expresión switch combinada con guardia when

void main() {
  int age = 22;
  String level = switch (age) {
    int a when a < 18 => "Menor de edad",
    int a when a < 30 => "Joven adulto",
    _ => "Adulto"
  };
  print(level);
}Lenguaje del código: Dart (dart)

Resultado de ejecución

Joven adulto

3 : Uso directo de expresión switch en el return de una función

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

String getDesc(int num) => switch (num) {
  1 => "Uno",
  2 => "Dos",
  _ => "Otro número"
};
Lenguaje del código: Dart (dart)

Resultado de ejecución

Otro número

Nota: Aquí switch es una expresión y getDesc es una función flecha. Las funciones flecha son una sintaxis exclusiva de Dart que no existe en otros lenguajes tipo C.

V. Comprobación de exhaustividad (Exhaustiveness Checking)

Error en tiempo de compilación si faltan casos para valores de entrada posibles; el compilador obliga a completar todos los casos. Las clases sealed y los enum soportan comprobación exhaustiva nativamente sin necesidad de _ ni default.

1 : Error de falta de exhaustividad en booleano nullable (comenta/descomenta para ver el error)

void main() {
  bool? nullableBool = null;
  // Descomentar el siguiente código genera error de compilación: falta case para null y no hay fallback _/default
  /*
  switch (nullableBool) {
    case true:
      print("Verdadero");
    case false:
      print("Falso");
  }
  */
  // Solución: agregar case null o fallback con _
  switch (nullableBool) {
    case true:
      print("Verdadero");
    case false:
      print("Falso");
    case null:
      print("Valor nulo");
  }
}Lenguaje del código: PHP (php)

Resultado de ejecución

Valor nulo

2 : Clase sealed (sellada)

Tipo de dato algebraico que fuerza la coincidencia exhaustiva de patrones

import 'dart:math' as math;

// Clase sealed: las subclases solo pueden definirse en este archivo
sealed class Shape {}

// Subclase Cuadrado: longitud del lado
class Square implements Shape {
  final double length;
  Square(this.length);
}

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

// Función flecha que calcula el área mediante coincidencia switch sobre el objeto subclase recibido
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => math.pi * r * r
  // Agregar una nueva subclase de Shape genera error de compilación por case faltante
};

void main() {
  final Shape circle = Circle(5);
  print(calculateArea(circle));
  final Shape square = Square(4);
  print(calculateArea(square));
}
Lenguaje del código: Dart (dart)

Resultado de ejecución

78.53981633974483
16.0Lenguaje del código: CSS (css)

3 : Coincidencia exhaustiva con enum

No hace falta el guion bajo de respaldo _

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

enum Animal { dog, cat }
Lenguaje del código: Dart (dart)

Salida: Gato

Los enum tienen un conjunto finito y fijo de valores, por lo que no se requiere rama de respaldo.

VI. Guardias when

Compatibles con if-case, instrucciones switch y expresiones switch

Función de when: realizar comprobación booleana adicional después de validar el patrón. Si el guardia devuelve false, se avanza a la siguiente rama sin salir del switch.

1. if-case + when

void main() {
  List<int> arr = [10, 20];
  if (arr case [int x, int y] when x + y > 20) {
    print("La suma de los dos números supera 20");
  }
}Lenguaje del código: Dart (dart)
La suma de los dos números supera 20

Primero comprueba que sea una lista con dos números enteros; si coincide el patrón, when verifica si su suma es superior a 20.

2. Instrucción 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 impar");
  }
}
Lenguaje del código: PHP (php)

Salida: Número impar

Primero confirma que el tipo es entero, luego ejecuta la condición del when.

3. Expresión switch + when

void main() {
  int num = 15;
  String res = switch(num) {
    int n when n % 2 == 0 => "Número par",
    _ => "Número impar"
  };
  print(res);
}
Lenguaje del código: PHP (php)

Flujo de control por ramificaciones

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *