zig-sentencias-if-expresiones

Condicionales en Zig: if como expresión y control seguro

  • 4 min

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", .{});
}
Copied!

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});
Copied!

Para que esto funcione, se deben cumplir dos reglas:

  1. Todas las ramas deben devolver un valor. No puedes tener un if que devuelva algo y un else que no haga nada.
  2. Los tipos deben ser compatibles. No puedes devolver un u8 en el if y un bool en el else.

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";
Copied!

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", .{});
}
Copied!

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í fuera
Copied!

Esto limita la visibilidad de los nombres temporales y evita que se usen fuera del lugar donde tienen sentido.