Ir al contenido principal

Bucles for en Zig

Los bucles for son una herramienta fundamental en Zig para iterar sobre colecciones de datos como arrays, slices y tuplas. A diferencia de otros lenguajes donde los bucles for son simples construcciones de control, en Zig los bucles for son más potentes y versátiles, ofreciendo características únicas que facilitan el trabajo con datos estructurados.

Bucle for básico

En Zig, la sintaxis básica de un bucle for consiste en la palabra clave for, seguida de la colección a iterar y un bloque de código. Dentro de los paréntesis, se especifica la colección y una variable para capturar cada elemento:

const expect = @import("std").testing.expect;

test "bucle for básico" {
    const items = [_]i32{ 4, 5, 3, 4, 0 };
    var suma: i32 = 0;

    for (items) |valor| {
        suma += valor;
    }

    try expect(suma == 16);
}

Acceso al índice de iteración

Una característica útil de los bucles for en Zig es la capacidad de acceder al índice de iteración. Esto se logra especificando un segundo parámetro de captura:

test "bucle for con índice" {
    var suma: usize = 0;
    const items = [_]u8{ 1, 2, 3, 4, 5 };

    for (items, 0..) |_, i| {
        suma += i;
    }

    try expect(suma == 10); // 0 + 1 + 2 + 3 + 4 = 10
}

En este ejemplo, usamos 0.. que es la sintaxis para crear un rango que comienza en 0 y termina en el mismo número de elementos que hay en items.

Iterar sobre un rango

Puedes usar la sintaxis de rango para iterar directamente sobre un conjunto de números consecutivos:

test "bucle for con rango" {
    var suma: usize = 0;
    
    for (0..5) |i| {
        suma += i;
    }
    
    try expect(suma == 10); // 0 + 1 + 2 + 3 + 4 = 10
}

Modificación de elementos

Si necesitas modificar los elementos de la colección durante la iteración, puedes capturar una referencia al elemento usando un puntero:

test "bucle for con modificación" {
    var items = [_]i32{ 3, 4, 2 };
    
    for (&items) |*valor| {
        valor.* += 1;
    }
    
    try expect(items[0] == 4);
    try expect(items[1] == 5);
    try expect(items[2] == 3);
}

Iterar sobre múltiples colecciones

Zig permite iterar sobre múltiples colecciones simultáneamente, siempre que tengan la misma longitud:

test "bucle for con múltiples colecciones" {
    const a = [_]u8{ 1, 2, 3 };
    const b = [_]u8{ 4, 5, 6 };
    var suma: usize = 0;

    for (a, b) |valor_a, valor_b| {
        suma += valor_a * valor_b;
    }

    try expect(suma == 32); // (1*4) + (2*5) + (3*6) = 4 + 10 + 18 = 32
}

Utilizar break y continue

Los bucles for, al igual que los while, admiten las instrucciones break y continue para controlar el flujo de iteración:

test "bucle for con break y continue" {
    const items = [_]i32{ 4, 5, -3, 4, 0 };
    var suma: i32 = 0;

    for (items) |valor| {
        if (valor < 0) {
            continue; // Salta los valores negativos
        }
        if (suma >= 8) {
            break; // Termina el bucle si la suma es mayor o igual a 8
        }
        suma += valor;
    }

    try expect(suma == 9); // 4 + 5 = 9, luego break
}

For como expresión

Al igual que if y while, los bucles for en Zig también son expresiones y pueden tener una cláusula else. Si el bucle termina naturalmente (sin ejecutar break), se evalúa la expresión else:

test "bucle for como expresión" {
    const items = [_]?i32{ 3, 4, null, 5 };
    
    var suma: i32 = 0;
    const resultado = for (items) |valor_opcional| {
        if (valor_opcional) |valor| {
            suma += valor;
        }
    } else blk: {
        try expect(suma == 12);
        break :blk suma;
    };
    
    try expect(resultado == 12);
}

Bucles for etiquetados

Al igual que con while, puedes etiquetar bucles for para controlar el flujo en bucles anidados:

test "bucle for etiquetado" {
    var contador: usize = 0;
    
    externo: for (0..3) |_| {
        for (0..3) |_| {
            contador += 1;
            break :externo; // Sale del bucle externo
        }
    }
    
    try expect(contador == 1);
}

Bucles for en tiempo de compilación (inline for)

Zig permite desarrollar bucles for en tiempo de compilación usando la palabra clave inline. Esto es útil cuando necesitas ejecutar código en tiempo de compilación o trabajar con tipos:

test "inline for" {
    const tipos = [_]type{ i32, f32, bool };
    var suma: usize = 0;
    
    inline for (tipos) |T| {
        suma += @sizeOf(T);
    }
    
    try expect(suma == 9); // 4 (i32) + 4 (f32) + 1 (bool) = 9
}

Los bucles for en Zig son herramientas poderosas para iterar sobre colecciones, con características que permiten un código más expresivo y legible. La capacidad de acceder a índices, modificar elementos, iterar sobre múltiples colecciones simultáneamente y utilizar el bucle como una expresión hace que los bucles for en Zig sean mucho más versátiles que en muchos otros lenguajes.

Los bucles for son particularmente útiles cuando trabajas con arrays, slices y otros tipos de colecciones, mientras que los bucles while suelen ser más adecuados para condiciones más generales o cuando necesitas un control más preciso sobre el flujo de ejecución.