← Flutter & Dart

Dart avanzado

¿Qué es un closure en Dart y para qué sirve?

Ver respuesta — intenta responderla en voz alta primero

Un closure es una función que "recuerda" las variables del ámbito donde fue creada, incluso después de que ese ámbito haya terminado. Sirve para mantener estado privado y para crear funciones configurables (fábricas de funciones).

En Dart las funciones son ciudadanos de primera clase: puedes guardarlas en variables, pasarlas como argumento y devolverlas desde otra función. Cuando defines una función dentro de otra, la función interna conserva acceso a las variables de la externa. Aunque la externa ya haya terminado, la interna sigue "recordando" esas variables. Esa combinación de función + variables recordadas es un closure.

Se usa para:

  • Mantener estado privado (variables que solo esa función puede tocar).
  • Crear funciones a partir de otras (fábricas de funciones).
  • Callbacks, onPressed, y prácticamente cualquier lambda que capture variables de su entorno en Flutter.
// Contador con estado privado gracias al closure
Function crearContador() {
  int cuenta = 0; // queda "encerrada" en el closure
  return () {
    cuenta++;
    return cuenta;
  };
}

// Fábrica: cada función recuerda su propio "factor"
int Function(int) multiplicarPor(int factor) {
  return (int numero) => numero * factor;
}

void main() {
  final contador = crearContador();
  print(contador()); // 1
  print(contador()); // 2
  print(contador()); // 3
  // "cuenta" no es accesible desde afuera: es privada

  final duplicar = multiplicarPor(2);
  final triplicar = multiplicarPor(3);
  print(duplicar(5)); // 10
  print(triplicar(5)); // 15
}

Asumir que cada llamada comparte el mismo estado. No: cada vez que llamas a crearContador() obtienes un closure nuevo con su propia cuenta. Dos contadores creados por separado no comparten valor. Confundir esto lleva a bugs donde crees que un contador "se reinició" cuando en realidad creaste otro.

"Un closure es una función que recuerda las variables del ámbito donde fue creada, aunque ese ámbito ya haya terminado. En Dart lo uso mucho porque las funciones son de primera clase: puedo devolver una función que mantiene una variable privada, como un contador, o crear una fábrica como multiplicarPor(2). En Flutter, cada callback onPressed que usa una variable de su widget es en la práctica un closure."

Reto rápido

Crea una función crearSaludo(String saludo) que devuelva otra función que reciba un nombre y devuelva el saludo completo. Ejemplo: crearSaludo("Hola")("Mike") debería devolver "Hola, Mike".

Ver solución
String Function(String) crearSaludo(String saludo) {
  return (String nombre) => "$saludo, $nombre";
}

void main() {
  print(crearSaludo("Hola")("Mike")); // "Hola, Mike"
}