Comprobar si existen campos con @hasField

Comprobar si existen campos con @hasField

El inventor abrió los ojos al recibir la última bofetada que se escuchó en toda la plaza.

- ¡Sonno il relojero e inventore al servicio de la Sua Majestad! -gritó, dándose cuenta de que estaba atado a un poste encima de un montón de madera y paja. El mismo inquisidor que le había golpeado, ahora encendía una antorcha.

-Por crear inventos del demonio y hacer el pacto con Satanás - gritó el inquisidor, con la antorcha encendida, giró hacia la muchedumbre reunida alrededor. Su voz tronaba ensordecedora en La Plaza de la Cruz Verde, lugar habitual para las ejecuciones -. La Santa Inquisición no tolera los pactos con el demonio. Esto es lo que pasa con los herejes y brujos que practican las artes oscuras.

-No tolera. No tolera. Estúpida panda de mandriles - chilló Juanelo viendo como la llama empezaba a devorar la paja de la hoguera. El inventor empezó a recordar los detalles. Esa mañana, Manitas descansaba en una silla reparando su propio brazo y el inventor trabajaba en el nuevo arma, cuando la puerta se abrió de una patada. Al momento, irrumpieron hombres armados, ataviados con sotanas negras.

-En nombre de la Santa Inquisición…- vaya, todo lo malo era en nombre de algo, pensó el inventor.

Gritaban acusaciones mientras lo maniataban. Él intentó explicar que no había hecho ningún pacto, salvo con el rey. Manitas se levantó para protegerlo pero uno de los inquisidores lo golpeó con tal fuerza que su cabeza salió volando hasta una esquina. Fue entonces cuando, bajo los golpes, él también perdió el conocimiento y ahora estaba en esta pesadilla.

landing.zig

const std = @import("std");

const print = std.debug.print;

fn get_landing_spot(T: type, x_spot: T) struct { i8, i8, i8 } {

    return .{

        x_spot.n_x,

        x_spot.n_y,

        x_spot.n_z,

    };

}

const Ground = struct { n_x: i8, n_y: i8, n_z: i8, n_area: i8 };

const Stake = struct { n_x: i8, n_y: i8, n_z: i8 };

const Water = struct { n_x: i8, n_y: i8, n_z: i8, n_area: i8 };

const o_juanelo = .{

    .n_x = 4,

    .n_y = 5,

    .n_z = 0,

};

pub fn main() !void {

    const t_landing_spots = .{

        Ground{

            .n_x = 1,

            .n_y = 2,

            .n_z = 0,

            .n_area = 4,

        },

        Ground{

            .n_x = 4,

            .n_y = 4,

            .n_z = 0,

            .n_area = 2,

        },

        Stake{

            .n_x = 4,

            .n_y = 5,

            .n_z = 5,

        },

        Water{

            .n_x = 5,

            .n_y = 1,

            .n_z = 0,

            .n_area = 4,

        },

    };

    var o_land = get_landing_spot(@TypeOf(t_landing_spots[0]), t_landing_spots[0]);

    inline for (t_landing_spots, 0..) |o_spot, n_i| {

        if (n_i == 0) continue;

        //comprobamos la distancia

        if ((@abs(o_spot.n_x - o_juanelo.n_x) 

            <= @abs(o_land.@"0" - o_juanelo.n_x)) 

           and

            (@abs(o_spot.n_y - o_juanelo.n_y) 

            <= @abs(o_land.@"1" - o_juanelo.n_y)))

              o_land = get_landing_spot(@TypeOf(o_spot), o_spot);

    }

    print("Aterrizar en: {any}\n", .{o_land});

}

$ zig run landing.zig

Aterrizar en: .{ 4, 5, 5 }

Juanelo justo había cerrado los ojos cegado por el humo cada vez más denso que emanaba debajo de sus pies… y entonces por un momento pensó que un rayo lo había golpeado. Sabía que ese tipo de cosas, podían suceder, cuando un árbol o un palo solitario se encontraba en espacios abiertos, justo como el de su hoguera en la plaza. Todavía sin abrir los ojos, notó como volaba por los aires y después de lo que pareció una eternidad, todavía atado al mástil, aterrizó encima de un montón de paja. Abrió los ojos y comprendió lo que había pasado: Estaba golpeado, magullado y aturdido pero al menos fuera del fuego, de momento. Manitas, el fiel Manitas - llegó volando en la nave que ni siquiera habían probado bien y se estrelló directo contra el poste. Probablemente un error de cálculo. Sonrió al verle saliendo debajo de los restos de la nave. Estaba cojeando y con un brazo prácticamente colgando de un hilo, pero vivo.

El código de landing.zig procesa varios puntos de aterrizaje posibles en las coordenadas de la plaza. Elige aquel más cercano a la posición del inventor. El problema que tiene es que, al ser el palo de la hoguera alto pero “carecer” de una superficie adecuada como para aterrizar la máquina voladora, el sistema al detecta erróneamente la altura de aterrizaje y se estampa contra el poste. Por suerte eso aparta a Juanelo del fuego pero… Manitas sale un poco perjudicado.

Compile Error

        Para provocar un error de compilación si el struct analizado no tiene el campo necesario, utilizamos @hasField y @compileError:

  fn get_landing_spot(T: type, x_spot: T) struct { i8, i8, i8 } {

    if (!@hasField(T, "n_area"))

        @compileError("El terreno no tiene una superficie\n");

    return .{

        x_spot.n_x,

        x_spot.n_y,

        x_spot.n_z,

    };

  }

En este caso, al intentar compilar, aparecerá el mensaje:

 error: El terreno no tiene una superficie

Al provocar errores en el tiempo de compilación, el programa no se ejecutará nunca. Si lo que queremos es controlar este error en tiempo de ejecución, podemos usar optionals y controlar lo que devuelve la función get_landing_spot:

landing_ok.zig

const std = @import("std");

const print = std.debug.print;

fn get_landing_spot(T: type, x_spot: T) ?struct { i8, i8, i8 } {

    // if (!@hasField(T, "n_area"))

    // @compileError("El terreno no tiene una superficie\n");

    if (!@hasField(T, "n_area"))

        return null;

    return .{

        x_spot.n_x,

        x_spot.n_y,

        x_spot.n_z,

    };

}

const Ground = struct { n_x: i8, n_y: i8, n_z: i8, n_area: i8 };

const Stake = struct { n_x: i8, n_y: i8, n_z: i8 };

const Water = struct { n_x: i8, n_y: i8, n_z: i8, n_area: i8 };

const o_juanelo = .{ .n_x = 4, .n_y = 5, .n_z = 0 };

pub fn main() !void {

    const t_landing_spots = .{

        Ground{ .n_x = 1, .n_y = 2, .n_z = 0, .n_area = 4 },

        Ground{ .n_x = 4, .n_y = 4, .n_z = 0, .n_area = 2 },

        Stake{ .n_x = 4,.n_y = 5, .n_z = 5 },

        Water{ .n_x = 5, .n_y = 1, .n_z = 0, .n_area = 4 },

    };

    var o_land: struct { i8, i8, i8 } = .{ 

      t_landing_spots[0].n_x, 

      t_landing_spots[0].n_y, t_landing_spots[0].n_z };

    inline for (t_landing_spots, 0..) |o_spot, n_i| {

        if (n_i == 0) continue;

        //comprobamos la distancia

        if ((@abs(o_spot.n_x - o_juanelo.n_x) 

             <= @abs(o_land.@"0" - o_juanelo.n_x)) and

            (@abs(o_spot.n_y - o_juanelo.n_y) 

             <= @abs(o_land.@"1" - o_juanelo.n_y)))

        {

            if (get_landing_spot(@TypeOf(o_spot), o_spot)) |o_xspot|

                o_land = o_xspot;

        }

    }

    print("Aterrizar en: {any}\n", .{o_land});

}

$ zig run landing_ok.zig

Aterrizar en: .{ 4, 4, 0 }

Si la máquina voladora hubiese tenido este tipo de control no se habría estrellado. También hay otro peligro - una superficie de agua, que por suerte no está tan cerca de la posición del inventor, pero que habría que filtrar.A ver si consigues hacerlo modificando el código fuente.

Recursión genérica
Structs genéricos
© 2025 Zen of Zig