Una etiqueta en Zig es un nombre que damos a un bucle o bloque para controlar desde dónde salimos o continuamos. Es útil cuando tienes un bucle dentro de otro y, al encontrar lo que buscas, quieres salir de todo.
En lenguajes como C o C++, la palabra clave break solo rompe el bucle más interno. Para salir de ambos, solemos recurrir a trucos “sucios” como:
- Crear una variable booleana
encontrado = truey comprobarla en el bucle externo. - Usar un
goto😱. - Refactorizar el código en una función aparte y usar
return.
Zig ofrece una solución explícita y legible: las etiquetas (labels).
Sintaxis de las etiquetas
Una etiqueta en Zig es simplemente un identificador seguido de dos puntos :, que se coloca justo antes de una sentencia de bucle (while, for) o un bloque.
nombre_etiqueta: while (condicion) {
...
}Una vez etiquetado el bucle, podemos usar break :nombre_etiqueta o continue :nombre_etiqueta para referirnos específicamente a ese bucle, sin importar lo profundo que estemos anidados.
Rompiendo bucles anidados
Imaginemos que estamos buscando un valor específico en una matriz de 10x10.
const matriz = [3][3]u8{
.{ 1, 2, 3 },
.{ 4, 5, 6 },
.{ 7, 8, 9 },
};
pub fn main() void {
const objetivo = 5;
// Etiquetamos el bucle exterior
bucle_externo: for (matriz, 0..) |fila, i| {
for (fila, 0..) |valor, j| {
if (valor == objetivo) {
std.debug.print("Encontrado en [{d}, {d}]\n", .{i, j});
// Rompemos directamente el bucle principal
break :bucle_externo;
}
}
}
std.debug.print("Búsqueda terminada.\n", .{});
}Si hubiéramos usado un break normal (sin etiqueta), solo habríamos salido del for interior, y el bucle externo habría seguido buscando en la siguiente fila innecesariamente.
Esta sintaxis mantiene el “Zen de Zig”: el flujo es explícito. Al leer break :bucle_externo, sabes exactamente a dónde va a saltar la ejecución, sin tener que rastrear llaves de cierre.
Etiquetas en continue
Lo mismo aplica para continue. Si estamos en un bucle interno y queremos forzar la siguiente iteración del bucle externo, usamos la etiqueta.
procesamiento: for (items) |item| {
while (condicion_compleja) {
// ... lógica ...
if (item_es_invalido) {
// Deja de procesar este item y pasa al siguiente del for
continue :procesamiento;
}
}
}Etiquetas en bloques
Las etiquetas no son exclusivas de los bucles. También podemos etiquetar un bloque de código { ... }.
Esto permite inicializar constantes cuya lógica necesita varios pasos.
Si quieres calcular una constante const, pero la lógica requiere variables temporales o varias condiciones, en otros lenguajes podrías necesitar una función auxiliar o una expresión invocada inmediatamente.
En Zig, usamos un bloque etiquetado:
const numero_complejo = bloque_calculo: {
var x: i32 = 10;
x += 5;
if (x > 20) {
// "Rompemos" el bloque devolviendo un valor
break :bloque_calculo 100;
}
// Valor por defecto del bloque
break :bloque_calculo x * 2;
};La sintaxis importante es break :etiqueta valor;.
Esto funciona igual que un return en una función, pero para un bloque local.
- El código dentro del bloque se ejecuta.
- Las variables
xmueren al salir del bloque (no contaminan el ámbito). - El resultado se asigna a
numero_complejode forma inmutable (const).
Esta técnica es la forma idiomática en Zig de emular las expresiones complejas que en Rust se hacen simplemente devolviendo el último valor del bloque.