Ir al contenido principal

Control de flujo con if en Zig

Las estructuras de control de flujo permiten alterar el orden de ejecución del código según ciertas condiciones. En Zig, estas estructuras son potentes y versátiles, ofreciendo características que otros lenguajes no tienen. Vamos a explorar cómo funcionan las expresiones if y else en Zig.

Sentencias if-else

En Zig, las sentencias if aceptan valores de tipo bool (es decir, true o false). A diferencia de lenguajes como C o JavaScript, no hay valores que se conviertan implícitamente a valores booleanos. Esto significa que expresiones como if (1) o if ("") que funcionan en otros lenguajes, no son válidas en Zig.

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

test "sentencia if" {
    const condicion = true;
    var resultado: u16 = 0;
    if (condicion) {
        resultado += 1;
    } else {
        resultado += 2;
    }
    try expect(resultado == 1);
}

If como expresión

Una característica interesante de Zig es que las sentencias if también funcionan como expresiones. Esto significa que pueden devolver un valor que puede ser asignado a una variable. Esto elimina la necesidad de un operador ternario (como condicion ? a : b en otros lenguajes).

test "if como expresión" {
    const condicion = true;
    var resultado: u16 = 0;
    resultado += if (condicion) 1 else 2;
    try expect(resultado == 1);
}

If con opcionales

Zig permite usar if con valores opcionales (tipos que pueden ser null). Cuando usas if con un opcional, puedes capturar el valor no nulo dentro del bloque if.

test "if con opcionales" {
    const valor: ?u32 = 10;

    if (valor) |v| {
        try expect(v == 10);
    } else {
        unreachable; // No se ejecutará porque valor no es null
    }

    const valorNulo: ?u32 = null;
    if (valorNulo) |_| {
        unreachable; // No se ejecutará porque valorNulo es null
    } else {
        // Este bloque se ejecuta si el valor es null
        try expect(true);
    }
}

If con uniones de error

Otra característica poderosa de Zig es que permite usar if con uniones de error. Una unión de error es un tipo que puede contener o un valor o un error.

test "if con uniones de error" {
    const resultado: anyerror!u32 = 10;
    
    if (resultado) |valor| {
        try expect(valor == 10);
    } else |err| {
        // Este bloque se ejecuta si el resultado es un error
        _ = err;
        unreachable;
    }
}

Bloques else if

Como en otros lenguajes, puedes anidar bloques if o usar else if para evaluar múltiples condiciones.

test "cadenas de else if" {
    const numero: i32 = 50;
    var resultado: i32 = -1;

    if (numero < 0) {
        resultado = -1;
    } else if (numero < 10) {
        resultado = 1;
    } else if (numero < 100) {
        resultado = 2;
    } else {
        resultado = 3;
    }

    try expect(resultado == 2);
}

Acceso a valores por referencia

En Zig, puedes acceder a los valores capturados por referencia usando |*valor| en lugar de |valor|. Esto te permite modificar el valor dentro del bloque if.

test "if con acceso por referencia" {
    var valor: ?u32 = 10;
    
    if (valor) |*v| {
        v.* += 5;
    }
    
    try expect(valor.? == 15);
}

Combinar con otras características

La flexibilidad de Zig permite combinar las estructuras de control de flujo con otras características como comptime para realizar operaciones en tiempo de compilación.

test "if en tiempo de compilación" {
    comptime {
        var resultado: u32 = 0;
        if (true) {
            resultado = 10;
        }
        try expect(resultado == 10);
    }
}

La claridad y seguridad que ofrece Zig con sus estructuras de control de flujo ayuda a escribir código más robusto y menos propenso a errores. El hecho de que no haya conversiones implícitas a booleanos y que las sentencias if puedan trabajar con opcionales y uniones de error de manera directa, facilita la escritura de código más claro y fácil de entender.