Domina las funciones y sus parámetros en Dart

Una función es un bloque de código encapsulado que realiza una tarea específica y puede ser ejecutada en cualquier momento. En Dart, las funciones son objetos de primera clase, lo que significa que puedes tratarlas como cualquier otro valor: asignarlas a variables, pasarlas como argumentos a otras funciones o incluso devolverlas.

El diseño de la sintaxis de Dart está pensado para maximizar la claridad y la seguridad. Para que el sistema de tipos de Dart sea sólido, la forma en que defines los parámetros debe ser precisa; de lo contrario, el compilador te obligará a corregirlo antes de que el programa siquiera se ejecute. Usarás funciones para todo: desde cálculos matemáticos simples mediante arrow functions (funciones de flecha) hasta la configuración compleja de servicios mediante parámetros nombrados. Si fallas en definir qué parámetros son obligatorios o en qué tipo de dato se basan, el programa fallará en el momento de la compilación, evitando errores silenciosos en producción.

void main() {
  // 1. Parámetros posicionales: el orden de los argumentos es fundamental.
  // El segundo parámetro es opcional porque está entre corchetes [].
  ejecutarComando("Limpieza de caché", 3);
  ejecutarComando("Cierre de sesión"); // Usa el valor por defecto (1)

  // 2. Parámetros nombrados: el orden no importa, lo que importa es el nombre.
  // Ideales para funciones con muchos argumentos o configuraciones.
  configurarServidor(nombre: "Servidor de Producción", puerto: 8080);
  configurarServidor(nombre: "Localhost", nivel: 5, etiqueta: "DEV");

  // 3. Funciones como objetos y Arrow Functions
  // 'formatear' es una variable que almacena una función.
  // El uso de '=>' es un atajo para funciones de una sola línea.
  final formatear = (String texto) => ">>> $texto. <<<";
  print(formatear("Proceso completado"));

  // 4. El tipo Never
  // Si descomentas la siguiente línea, el programa lanzará una excepción y se detendrá.
  // finalizarPrograma("Error de conexión");
}

// Parámetros posicionales: 'mensaje' es obligatorio, 'intentos' es opcional con valor por defecto.
void ejecutarComando(String mensaje, [int intentos = 1]) {
  print("Ejecutando: $mensaje (Intentos: $intentos)");
}

// Parámetros nombrados: usamos llaves {}. 
// 'nombre' es obligatorio gracias a 'required'.
// 'puerto' tiene un valor por defecto.
// 'etiqueta' es opcional y puede ser nulo (String?).
void configurarServidor({
  required String nombre,
  int puerto = 3000,
  int nivel = 1,
  String? etiqueta,
}) {
  print("Configurando $nombre en puerto $puerto (Nivel: $nivel, Etiqueta: ${etiqueta ?? 'Ninguna'})");
}

// La función devuelve 'Never', lo que indica que nunca retorna un valor
// porque siempre lanza una excepción o entra en un bucle infinito.
Never finalizarPrograma(String motivo) {
  throw Exception("Error fatal: $motivo");
}

Desglose del código

En el ejemplo anterior, ejecutarComando utiliza parámetros posicionales opcionales definidos con corchetes []. Esto significa que si llamas a la función con un solo argumento, Dart asignará automáticamente 1 a intentos. Si intentas pasar un segundo argumento, este debe ser estrictamente un int.

La función configurarServidor es más avanzada y utiliza parámetros nombrados mediante llaves {}. Esto es crucial para la legibilidad: al llamar a la función, escribimos nombre: "Servidor...", lo que hace que el código sea autodocumentado. El modificador required es vital; le dice al compilador que, aunque el parámetro sea nombrado, es estrictamente necesario para que la función funcione. Si intentas llamar a configurarServidor sin pasar el nombre, el código no compilará. Además, nota cómo usamos String? etiqueta; el signo de interrogación indica que este parámetro es nullable, permitiendo que su valor sea null sin que el sistema de tipos de Dart se queje.

En la sección de funciones como objetos, formatear utiliza una arrow function =>. Esta sintaxis es una forma abreviada de escribir una función que solo tiene una expresión de retorno, eliminando la necesidad de usar las llaves {} y la palabra clave return.

Finalmente, finalizarPrograma tiene un tipo de retorno Never. Esto es una instrucción muy fuerte para el compilador: le estamos diciendo que el flujo de ejecución nunca pasará de esa línea de forma normal. Esto es extremadamente útil en lógica de errores para asegurar que el sistema sepa que, tras esa llamada, el control no regresará al flujo principal.

El error frecuente

Un error común al trabajar con parámetros nombrados es intentar pasar un parámetro opcional sin su etiqueta, o intentar pasar un parámetro requerido sin la palabra clave required si el tipo no permite nulos.

// ERROR: Esto fallará al compilar
void errorComun({String nombre}) { ... }

// Error 1: Si 'nombre' no es 'required' ni tiene valor por defecto, 
// Dart te obligará a que sea 'String?' (nullable).
// Error 2: Intentar llamarla así:
// errorComun("Juan"); // Error: Los parámetros nombrados requieren su nombre.

Si defines un parámetro nombrado como String nombre (no nullable) pero no le pones required ni un valor por defecto, el compilador de Dart te dará un error porque, en teoría, alguien podría llamar a la función sin ese parámetro, dejando una variable con valor nulo donde no debería haberlo.

24

Dejar un comentario

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

Scroll al inicio