Coincidencia mediante Patterns

La sintaxis Patterns solo está disponible a partir de la versión Dart ≥ 3.0

I. Función principal de los Patterns

El Pattern es una categoría sintáctica independiente en Dart (mismo nivel que sentencias y expresiones) que describe la estructura de un conjunto de valores. Cuenta con dos capacidades centrales que se pueden usar simultáneamente: coincidencia (Match) y desestructuración (Destructure).

  1. Coincidencia Match: Comprobar si un valor cumple con la forma esperada
    • ¿Coincide con una constante específica?
    • ¿Pertenece a un tipo concreto?
    • ¿Tiene una estructura definida (Lista/Mapa/Objeto/Registro Record)?
    • ¿Cumple una condición adicional?
  2. Desestructuración Destructure: Tras una coincidencia exitosa, extraer rápidamente campos y elementos internos del valor para vincularlos a variables

1. Ejemplo de coincidencia por constante

void main() {
	int number = 1;
	switch (number) {
	  case 1:
		print('one'); // Coincidencia de constante: number == 1
	  default:
		print('otro número');
	}
}Lenguaje del código: Dart (dart)

Resultado de ejecución

one

2. Coincidencia con subpatrones anidados

Los patrones admiten subpatrones anidados para validar la estructura interna paso a paso

void main() {
  const a = 'a';
  const b = 'b';
  var obj = [ 'a', 'b'];
  switch (obj) {
    case [a, b]:
      print('$a, $b');
    default:
      print('Sin coincidencia');
  }
}Lenguaje del código: Dart (dart)

Resultado de ejecución

a, b

3. Ejemplo básico de desestructuración

var numList = [1, 2, 3];
// Patrón Lista para descomponer elementos y vincular a nuevas variables
var [x, y, z] = numList; 
print(x + y + z); // 6 x = 1, y = 2, z = 3Lenguaje del código: PHP (php)

4. Coincidencia + desestructuración con patrón anidado

void main() {
  var list = ['b', 99];
  switch (list) {
    // Patrón OR lógico: primer elemento a o b, segundo vinculado a variable c
    case ['a' || 'b', var c]:
      print(c); // 99
  }
}Lenguaje del código: Dart (dart)

II. Ejemplos frecuentes de uso de Patterns

1. Declaración de variables locales

Se usa para asignación desestructurante, permite crear múltiples variables en una sola línea

// Desestructuración con patrón anidado Registro + Lista
var (str, [n1, n2]) = ('text', [10, 20]);
print(str); //text
print(n1 + n2); //30Lenguaje del código: Dart (dart)

2. Reasignación de variables existentes (intercambio sin variable temporal)

var (a, b) = ("izquierda", "derecha");
(b, a) = (a, b); // Intercambiar valores de dos variables
print('$a $b'); // derecha izquierdaLenguaje del código: Dart (dart)

3. Ramificaciones switch / if-case (uso más común, cláusula guardia when)

Cada case acepta patrones refutables: si no hay coincidencia, se evalúa el siguiente case

Case básico para múltiples tipos

void testSwitch(dynamic obj) {
  switch (obj) {
    case 1:
      print('número 1');
    case >= 10 && <= 20:
      print('número entre 10 y 20');
    case (var a, var b):
      print('registro: $a,$b');
    default:
      print('Sin coincidencias');
  }
}Lenguaje del código: Dart (dart)

Patrón OR lógico: compartir lógica entre varias ramas

enum Color { red, yellow, blue, green }
void main() {
  Color color = Color.red;
  bool isPrimary = switch (color) {
    Color.red || Color.yellow || Color.blue => true,
    _ => false,
  };
  print(isPrimary); // true
}
Lenguaje del código: PHP (php)

Cláusula guardia when (filtro condicional adicional tras coincidencia)

sealed class Shape {}
class Square { final double size; Square(this.size); }
class Circle { final double size; Circle(this.size); }

void checkShape(Shape shape) {
  switch (shape) {
    // Coincidir Square y Circle simultáneamente, agregar condición size>0
    case Square(size: var s) || Circle(size: var s) when s > 0:
      print('figura simétrica válida');
    default:
      print('figura inválida');
  }
}Lenguaje del código: Dart (dart)

Diferencia entre when y un if normal

void compareWhen((int, int) pair) {
  switch (pair) {
    case (int a, int b):
      if (a > b) print('El primer valor es mayor');
      // Si el if falla: se cierra todo el switch, no se ejecutan los siguientes case
    case (int a, int b) when a > b:
      print('【Guardia when】El primer valor es mayor');
      // Si when falla: solo se salta este case y se evalúa el siguiente
    case (int a, int b):
      print('El primer valor es menor o igual');
  }
}

void main() {
  print("===== Prueba (5, 2) a > b =====");
  compareWhen((5, 2));

  print("\n===== Prueba (2, 5) a < b =====");
  compareWhen((2, 5));
}Lenguaje del código: Dart (dart)

4. Bucles for /for-in (desestructuración de MapEntry muy práctica)


void main() {
	Map<String, int> hist = {'a': 23, 'b': 100};
	
	// Escritura completa
	for (var MapEntry(key: key, value: count) in hist.entries) {
	  print('$key : $count');
	}
	
	// Sintaxis abreviada: key:key simplificado a :key
	for (var MapEntry(:key, value: count) in hist.entries) {
	  print('$key : $count');
	}
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
a : 23
b : 100
a : 23
b : 100
Lenguaje del código: CSS (css)

III. Casos de uso empresarial de Patterns

1: Múltiples valores de retorno de función (desestructuración de registros)

Método tradicional (verboso)

(String, int) userInfo() => ("Lily", 13);
void main() {
  var info = userInfo();
  var name = info.$1;
  var age = info.$2;
}
Lenguaje del código: Dart (dart)

Escritura simplificada mediante patrón

var (name, age) = userInfo();
// Desestructuración de registro con campos nombrados
final (:name, :age) = getData(); // Devuelve (name: "Doug", age:25)Lenguaje del código: Dart (dart)

Ejemplo concreto


(String, int) userInfo() => ("Lily", 18);


({String name, int age}) getData() => (name: "Doug", age: 25);

void main() {
  {
    var (name, age) = userInfo();
    print("Nombre: $name, edad: $age");
  }

  // Las variables internas name/age no interfieren con las externas
  {
    final (:name, :age) = getData();
    print("Nombre: $name, edad: $age");
  }
}Lenguaje del código: Dart (dart)

2: Desestructuración de instancias de clase (patrón de objeto)

class Foo {
  final String one;
  final int two;
  Foo({required this.one, required this.two});
}

void main() {
  final Foo myFoo = Foo(one: "test", two: 66);
  var Foo(:one, :two) = myFoo;
  print('$one $two'); //test 66
}Lenguaje del código: Dart (dart)

3: Tipos de datos algebraicos (clases sealed + cálculo por ramas switch)

Gestionar uniformemente un grupo de subclases relacionadas sin métodos de instancia dispersos

import 'dart:math';

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) => pi * r * r,
};
Lenguaje del código: Dart (dart)

Ejemplo completo de implementación

import 'dart:math';

// Clase padre sellada, subclases solo definibles en este archivo
sealed class Shape {}

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

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

// Cálculo uniforme de área con expresión switch + patrón objeto
double calculateArea(Shape shape) => switch (shape) {
  // Coincidir Square, extraer length a variable l
  Square(length: var l) => l * l,
  // Coincidir Circle, extraer radius a variable r
  Circle(radius: var r) => pi * r * r,
};

void main() {
  // Crear instancias de figuras
  Shape square = Square(5);
  Shape circle = Circle(3);

  // Calcular áreas
  double squareArea = calculateArea(square);
  double circleArea = calculateArea(circle);

  print("Área del cuadrado: $squareArea");    // 25.0
  print("Área del círculo: ${circleArea.toStringAsFixed(2)}"); // 28.27
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Área del cuadrado: 25.0
Área del círculo: 28.27Lenguaje del código: CSS (css)

4: Validación y desestructuración de datos JSON (simplifica enormemente los condicionales anidados)

(Sin Patterns) Múltiples comprobaciones de tipo anidadas generan código extenso

void oldCheck(Map data) {
  if (data is Map<String, Object?> && data.containsKey('user')) {
    var user = data['user'];
    if (user is List && user.length == 2) {
      String name = user[0] as String;
      int age = user[1] as int;
      print('$name $age');
    }
  }
}Lenguaje del código: Dart (dart)

Patrón if-case: una sola línea para validación de estructura + tipo + vinculación de variables

void newCheck(Map data) {
  if (data case {'user': [String name, int age]}) {
    print('Usuario $name, edad $age');
  }
}Lenguaje del código: Dart (dart)

Este patrón valida simultáneamente todos estos puntos:

  1. data es un Map y no es nulo
  2. Existe la clave user
  3. El valor asociado a user es una lista de dos elementos
  4. Primer elemento String, segundo elemento int
  5. Vinculación automática de variables locales name y age

Ejemplo práctico de uso

void main() {
  // 1. Estructura JSON válida: coincidencia exitosa
  final validJson = {
    'user': ['Lily', 13]
  };
  newCheck(validJson); // Salida: Usuario Lily, edad 13

  // 2. Incompatibilidad de tipos en la lista: edad en cadena, sin coincidencia
  final wrongTypeJson = {
    'user': ['Tom', '16']
  };
  newCheck(wrongTypeJson); // Sin salida

  // 3. Lista user incompleta: sin dato de edad, sin coincidencia
  final shortJson = {
    'user': ['Jack']
  };
  newCheck(shortJson); // Sin salida

  // 4. Falta la clave user: sin coincidencia
  final noUserJson = {
    'info': ['Bob', 20]
  };
  newCheck(noUserJson); // Sin salida
}

// Validación de estructura/tipo y desestructuración en un paso con patrón Map+List if-case
void newCheck(Map data) {
  if (data case {'user': [String name, int age]}) {
    print('Usuario $name, edad $age');
  } else {
    print('Formato de datos no válido');
  }
}Lenguaje del código: PHP (php)

Coincidencia mediante Patterns

Deja una respuesta

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