Un if en Zig es una estructura que permite elegir entre caminos de ejecución y también devolver valores. En cualquier lenguaje, la capacidad de tomar decisiones es fundamental: “si pasa esto, haz aquello”.
En Zig, if no es solo una instrucción de control de flujo; también es una expresión.
Esto significa que un bloque if puede evaluar y devolver un valor, lo que nos permite escribir código mucho más conciso y eliminar redundancias sintácticas del pasado.
La sentencia if básica
Empecemos por lo familiar. La estructura básica de un condicional en Zig es casi idéntica a C, pero con una diferencia clave: los paréntesis alrededor de la condición son obligatorios y la condición debe ser estrictamente un booleano.
const activo: bool = true;
if (activo) {
std.debug.print("El sistema está activo\n", .{});
} else {
std.debug.print("Sistema apagado\n", .{});
}Recordatorio: solo booleanos
Como vimos en el capítulo de tipos primitivos, Zig no tiene concepto de “truthy” o “falsy”.
if (1)-> Error de compilación.if (ptr)-> Error de compilación.if (nombre.len)-> Error de compilación.
Debemos ser explícitos: if (cantidad > 0), if (ptr != null).
El if como expresión
En lenguajes como C++ o JavaScript, si queremos asignar un valor a una variable dependiendo de una condición, solemos usar el operador ternario (condicion ? a : b).
En Zig, el operador ternario no existe. No lo necesitamos, porque el propio if puede hacer ese trabajo de forma más legible.
Podemos asignar el resultado de un if directamente a una variable:
const edad: u8 = 18;
// El if devuelve un valor, que se guarda en 'tipo_entrada'
const tipo_entrada = if (edad >= 18) "Adulto" else "Menor";
std.debug.print("Tipo de entrada: {s}\n", .{tipo_entrada});Para que esto funcione, se deben cumplir dos reglas:
- Todas las ramas deben devolver un valor. No puedes tener un
ifque devuelva algo y unelseque no haga nada. - Los tipos deben ser compatibles. No puedes devolver un
u8en elify unboolen elelse.
Una única sintaxis
Al eliminar el operador ternario, Zig reduce la superficie del lenguaje. No hay una forma para sentencias y otra para expresiones: solo existe la sintaxis if, que se adapta al contexto.
Esto fomenta la inmutabilidad (const). En otros lenguajes, a veces declaramos var x; y luego usamos un if para rellenarla. En Zig, podemos declarar const x = if (...) directamente.
Expresiones complejas en bloques
¿Qué pasa si la lógica para calcular el valor es compleja y requiere varias líneas? Zig permite usar bloques de código como expresiones.
En estos casos no usamos return, porque terminaría la función entera. El bloque debe llevar una etiqueta y devolver su resultado mediante break :etiqueta valor.
const puntuacion: u32 = 85;
const grado = if (puntuacion > 90) "A" else if (puntuacion > 80) nota: {
// Podemos hacer cálculos aquí dentro
std.debug.print("Casi perfecto...\n", .{});
// Devolvemos el valor del bloque etiquetado
break :nota "B";
} else "C";Zig no devuelve implícitamente la última expresión de un bloque. Si una rama usa llaves y debe producir un valor, hay que devolverlo con un break etiquetado.
if con opcionales y errores
Aunque dedicaremos capítulos enteros a la gestión de memoria y errores, es imposible hablar del if en Zig sin mencionar su uso para desempaquetar valores.
En Zig, a menudo tendrás variables que pueden ser un valor o null (Opcionales). El if en Zig tiene una sintaxis especial para capturar ese valor de forma segura:
const posible_numero: ?i32 = 42; // El '?' indica que puede ser null
// "Si posible_numero tiene valor, captúralo en 'n' y entra"
if (posible_numero) |n| {
std.debug.print("El número es: {d}\n", .{n});
} else {
std.debug.print("Es null\n", .{});
}Esta estructura (if (variable) |captura|) es omnipresente en Zig y es la forma en que evitamos los famosos errores de “Null Pointer Exception”.
Ámbito de las variables
Finalmente, recordemos que Zig usa ámbitos de bloque léxico ({}). Si declaras una variable dentro de las llaves de un if, esa variable solo existe dentro de esas llaves.
if (condicion) {
const secreto = 123;
}
// Error: use of undeclared identifier 'secreto'
// secreto no existe aquí fueraEsto limita la visibilidad de los nombres temporales y evita que se usen fuera del lugar donde tienen sentido.