Una variable es un nombre que usamos para guardar y manipular un dato dentro de nuestro programa.
Una vez que tenemos nuestro entorno listo, el siguiente paso lógico es aprender a almacenar y manipular datos.
Dart es un lenguaje tipado estáticamente. Esto significa que, a diferencia de JavaScript (donde una variable puede ser un número hoy y un texto mañana), en Dart una vez que una variable se define como texto, siempre será texto.
Esto, que al principio puede parecer una restricción, nos permite detectar errores antes de ejecutar la aplicación.
Declaración de variables
En Dart tenemos dos formas principales de declarar variables: indicando el tipo explícitamente o dejando que el lenguaje lo deduzca (inferencia).
Tipado explícito
Es la forma clásica. Indicamos el tipo de dato delante del nombre de la variable.
String nombre = "Luis";
int edad = 30;
double altura = 1.75;
bool esPropietario = true;
Inferencia de tipos con var
Dart es listo. Si le asignas un valor inicial a una variable, él ya sabe de qué tipo es. Para esto usamos la palabra reservada var.
var ciudad = "Madrid"; // Dart infiere que es String
// ciudad = 10; // ❌ Error: No puedes asignar un 'int' a una variable 'String'
Aunque usemos var, la variable sigue teniendo un tipo fijo. No es lo mismo que dynamic (un tipo especial que desactiva el chequeo de tipos y que deberíamos evitar siempre que sea posible).
Inmutabilidad: final y const
En el desarrollo moderno, y especialmente en Flutter, preferimos que las cosas no cambien (inmutabilidad) a menos que sea estrictamente necesario. Para esto tenemos final y const.
Ambas impiden que el valor de una variable sea modificado después de asignarse, pero tienen una diferencia crucial:
final
Se define en tiempo de ejecución. Es decir, el valor se asigna cuando el programa pasa por esa línea, y ya no cambia.
final fechaActual = DateTime.now(); // ✅ Correcto, se calcula al ejecutar
const
Se define en tiempo de compilación. El valor debe conocerse antes de que el programa arranque. Es un valor “grabado en piedra”.
const pi = 3.1416; // ✅ Correcto, es un valor fijo
// const fecha = DateTime.now(); // ❌ Error: DateTime.now() no se conoce al compilar
Como criterio práctico, usa const para valores fijos (configuraciones, textos estáticos, estilos) y final para valores que obtienes de una base de datos o cálculos pero que no vas a modificar después.
Null Safety
Una de las características más importantes de Dart moderno es Null Safety.
Históricamente, el error más común en programación ha sido intentar usar una variable que estaba vacía (null), provocando el temido “Null Pointer Exception”. Dart soluciona esto por diseño.
Variables no nulas por defecto
En Dart, por defecto, una variable no puede contener null.
int edad;
// print(edad); // ❌ Error: La variable debe ser inicializada antes de usarse.
edad = null; // ❌ Error: El valor 'null' no puede asignarse a un tipo 'int'.
Esto nos garantiza que si recibimos un int, tenemos un número seguro al 100%.
Variables anulables con ?
¿Pero qué pasa si realmente necesitamos que una variable pueda no tener valor? (Por ejemplo, un usuario que quizás no ha rellenado su segundo apellido).
Usamos el signo de interrogación ? después del tipo.
String? segundoApellido;
segundoApellido = null; // ✅ Ahora sí es válido
Operadores de Null Safety
Trabajar con variables que pueden ser nulas requiere cuidado. Dart nos ofrece tres operadores muy cómodos para gestionarlo con elegancia.
Operador de aserción !
Es el modo “confía en mí”. Le decimos a Dart: “Sé que esta variable parece nula, pero te aseguro que ahora mismo tiene datos”.
String? nombrePosible = "Ana";
// print(nombrePosible.length); // ⚠️ Dart se queja porque podría ser null
print(nombrePosible!.length); // ✅ Forzamos el acceso (Peligroso si te equivocas)
Úsalo solo cuando estés 100% seguro. Si te equivocas y es null, la App crasheará.
Acceso condicional ?.
Es la forma segura. “Si la variable tiene datos, accede a la propiedad. Si es null, devuélveme null (y no explotes)”.
String? nombre;
print(nombre?.length); // Imprime: null (no da error)
Operador de coalescencia nula ??
Este operador resulta muy útil. Sirve para proporcionar un valor por defecto si la variable es nula.
String? nombreUsuario; // Es null
String nombreAMostrar = nombreUsuario ?? "Invitado";
print(nombreAMostrar); // Imprime: "Invitado"
Esto es súper útil en Flutter para mostrar textos cuando los datos de una API aún no han llegado.
Ejemplo completo
Veamos un ejemplo que combina todo lo anterior:
void main() {
// Inferencia y variables mutables
var titulo = "Curso de Dart";
// Constante (tiempo de compilación)
const version = 3.0;
// Variable que puede ser nula
String? autor;
// Asignamos valor más tarde
// autor = "Luis";
// Uso de ?? para valor por defecto
print("Autor: ${autor ?? 'Anónimo'}"); // Muestra: Autor: Anónimo
}