Funciones Anónimas y Encapsuladas
Tenemos una función anónima definida de esta manera:
|
// función anónima solo accesible desde este scope const load_single = struct { fn _(o_me: *MachineGun, x_bullet: anytype) void { if (o_me.l_ammo.capacity == o_me.l_ammo.items.len) print("No hay más sitio\n", .{}) else if (@TypeOf(x_bullet) == Proyectile) o_me.l_ammo.appendAssumeCapacity(x_bullet) else print("¡No puede disparar eso!\n", .{}); } }._; |
Las funciones anónimas son aquellas cuyo nombre no nos importa porque queremos usar lo que hacen, en un único lugar del código. En Zig, para crear una función anónima usamos esta forma:
const result = struct {
fn nombre_funcion ( param: tipo, … , paramN: tipoN ) tipo_devuelto{
// … código de la función
return dato;
}
}.nombre_funcion( params …); // extraemos la función y la llamamos
Escribimos, un struct, definimos una función dentro, y la llamamos inmediatamente.
Pero en el ejemplo anterior hacemos algo distinto:
|
const load_single = struct { fn _( // ... }._; |
En lugar de llamarla directamente, asignamos la función extraída a una constante. Hemos usado el guión bajo _ como nombre interno para hacer todo más conciso, pero se puede poner cualquier otro nombre válido.
¿Por qué es útil esto? Como en Zig no es posible definir funciones dentro de otras funciones, usamos está técnica para encapsular funciones auxiliares y no contaminar el scope global con código local.
En lugar de escribir solo funciones anónimas repetidas:
|
switch (@typeInfo(@TypeOf(x_ammo))) { .array => for (x_ammo) |o_bullet| struct { fn load_single(o_me: *MachineGun, x_bullet: anytype) void { // ... } }.load_single(self, o_bullet), else => struct { fn load_single(o_me: *MachineGun, x_bullet: anytype) void { // ... }.load_single(self, x_ammo), } |
… extraemos la función y así evitamos repetir el código. Todo queda mucho más limpio.