anytype y T: type
En este ejemplo vemos cómo, en la declaración de la función load_ammo, usamos x_ammo: anytype:
|
// cargar diferentes cantidades / tipos de munición fn load_ammo(self: *MachineGun, x_ammo: anytype) void { |
Hacemos uso de genéricos porque queremos permitir que se pueda añadir un único proyectil o varios a la vez representados por un array.
También, podríamos definir de manera explícita el tipo como T y usarlo así:
|
fn load_ammo(self: *MachineGun, T: type, x_ammo: T) void { |
Las limitaciónes de anytype son:
- anytype solo se puede usar en la declaración de la función, dentro del cuerpo, no podemos usarlo como tipo de una variable.
|
const x_ammo: anytype; <- error de compilación |
- No se puede poner en la declaración como tipo devuelto, hay que usar @TypeOf (nombre_variable)
|
pack_ammo(x_ammo: anytype) @TypeOf(x_ammo); |
- Con T: type nombramos el tipo de manera explícita dejando claro qué estamos intentando usar en la llamada:
|
load_ammo([5]Proyectile, a_ammo); // sabemos que es un array de 5 |
Dentro del cuerpo de la función es necesario comprobar el tipo de dato concreto que estamos recibiendo para poder operar correctamente. Para ello usamos la función @TypeOf - para obtener el tipo del valor y @typeInfo - para inspeccionar la estructura y saber si se trata de un array.
|
// si es un array cargamos todos los elementos switch (@typeInfo(@TypeOf(x_ammo))) { .array => for (x_ammo) |o_bullet| load_single(self, o_bullet), else => load_single(self, x_ammo), } |
@typeInfo devuelve un union std.builtin.Type. En el propio código fuente de Zig, en el fichero builtin.zig podemos encontrar este tipo:
|
pub const Type = union(enum) { type: void, void: void, bool: void, noreturn: void, int: Int, float: Float, pointer: Pointer, array: Array, ... |
En el capítulo 6 vimos que en un union solo un campo puede estar activo a la vez. Aquí detectamos si el campo activo es .array, iteramos sobre los datos que nos llegan y “cargamos” un proyectil por iteración.