Arrays en Zig: fundamentos y usos prácticos
Los arrays son una de las estructuras de datos fundamentales en cualquier lenguaje de programación, y Zig no es una excepción. En este artículo profundizaremos en cómo funcionan los arrays en Zig, desde su definición básica hasta ejemplos prácticos que te ayudarán a utilizarlos de manera efectiva en tus proyectos.
¿Qué es un array en Zig?
Un array en Zig es una colección secuencial de elementos del mismo tipo con un tamaño fijo conocido en tiempo de compilación. Esta estructura de datos proporciona acceso directo a cualquier elemento mediante su índice, lo que permite operaciones rápidas de lectura y escritura.
Sintaxis básica
En Zig, los arrays se definen utilizando la siguiente sintaxis:
[N]T
Donde:
N
es el número de elementos que contendrá el arrayT
es el tipo de datos de los elementos
Esta declaración nos indica que estamos creando un array de N
elementos, todos ellos de tipo T
.
Declaración e inicialización de arrays
Veamos las diferentes formas de declarar e inicializar arrays en Zig:
Arrays con tamaño inferido
Cuando declaramos un array literal, podemos permitir que Zig infiera el tamaño del array utilizando el comodín _
en lugar de especificar explícitamente el número de elementos:
const mensaje = [_]u8{ 'h', 'o', 'l', 'a' };
En este ejemplo, creamos un array de caracteres (bytes sin signo) llamado mensaje
. El compilador determina automáticamente que el tamaño del array es 4, basándose en el número de elementos proporcionados en la inicialización.
Arrays con tamaño explícito
También podemos declarar arrays especificando explícitamente su tamaño:
var mensaje2: [4]u8 = undefined;
Aquí creamos un array mutable (var
) de 4 bytes sin signo. La palabra clave undefined
indica que no estamos inicializando los elementos del array con valores concretos. Esto es útil cuando planeamos asignar valores a todos los elementos más adelante en el código.
Nota: Usar undefined
es eficiente porque no inicializa la memoria, pero también es peligroso si intentamos leer los valores antes de asignarlos. En Zig, siempre debemos inicializar las variables antes de leerlas.
Acceso y manipulación de elementos
Para acceder a los elementos de un array, utilizamos la sintaxis de corchetes con el índice del elemento deseado:
const primerCaracter = mensaje[0]; // 'h'
mensaje2[0] = 'x'; // Asignación a un elemento del array
Los índices en Zig, como en la mayoría de los lenguajes de programación, comienzan en 0.
Ejemplo práctico: suma de elementos de un array
Veamos cómo podemos trabajar con arrays en un ejemplo práctico:
const expect = @import("std").testing.expect;
const mensaje = [_]u8{ 'h', 'o', 'l', 'a' }; // Array literal con tamaño inferido
var mensaje2: [4]u8 = undefined; // Array con tamaño explícito sin inicializar
test "asigna mensaje a mensaje2 y suma sus valores ASCII" {
// Copiamos el contenido del array mensaje a mensaje2
mensaje2 = mensaje;
// Variable para almacenar la suma de los valores ASCII
var suma: usize = 0;
// Iteramos sobre cada elemento de mensaje2
for (mensaje2) |caracter| {
suma += caracter;
}
// Verificamos que la suma es igual a la suma de los valores ASCII de 'h', 'o', 'l', 'a'
try expect(suma == 'h' + 'o' + 'l' + 'a');
}
En este ejemplo:
- Declaramos dos arrays: uno constante con valores inicializados y otro variable sin inicializar.
- Copiamos el contenido del primer array al segundo.
- Utilizamos un bucle
for
para iterar sobre cada elemento del arraymensaje2
. - Sumamos los valores ASCII de cada carácter.
- Finalmente, verificamos que la suma calculada coincide con lo esperado.
Propiedades de los arrays
Los arrays en Zig tienen propiedades útiles que podemos utilizar:
Longitud del array
Podemos acceder a la longitud de un array mediante la propiedad .len
:
const longitud = mensaje.len; // Devuelve 4
Tamaño en memoria
Podemos obtener el tamaño en bytes que ocupa un array con la función @sizeOf
:
const tamañoEnBytes = @sizeOf(@TypeOf(mensaje)); // Devuelve 4 (1 byte por cada u8)
Arrays multidimensionales
Los arrays también pueden contener otros arrays, creando estructuras multidimensionales. Esto es especialmente útil para representar datos tabulares o coordenadas en un espacio multidimensional.
Declaración de arrays bidimensionales
Un array bidimensional se puede imaginar como una matriz o tabla:
const puntos = [4][2]f32{
[_]f32{ 12.5, 33.6 },
[_]f32{ -1.5, 23.6 },
[_]f32{ 4.5, 3.6 },
[_]f32{ 0.0, 0.0 },
};
En este ejemplo, creamos un array de 4 elementos, donde cada elemento es a su vez un array de 2 números de punto flotante (f32
). Podemos visualizarlo como:
[
[12.5, 33.6],
[-1.5, 23.6],
[4.5, 3.6],
[0.0, 0.0]
]
Cada "fila" representa un punto en un espacio bidimensional, con coordenadas X e Y.
Acceso a elementos en arrays multidimensionales
Para acceder a elementos en un array multidimensional, utilizamos múltiples índices en corchetes:
const valorY = puntos[1][1]; // Accede al valor Y del segundo punto (23.6)
Aquí, puntos[1]
nos da el segundo array (recuerda que los índices comienzan en 0), y [1]
nos da el segundo elemento de ese array.
Ejemplo completo con arrays multidimensionales
const expect = @import("std").testing.expect;
// Definimos un array 2D que representa coordenadas de puntos (x, y)
const puntos = [4][2]f32{
[_]f32{ 12.5, 33.6 }, // Punto 1: (12.5, 33.6)
[_]f32{ -1.5, 23.6 }, // Punto 2: (-1.5, 23.6)
[_]f32{ 4.5, 3.6 }, // Punto 3: (4.5, 3.6)
[_]f32{ 0.0, 0.0 }, // Punto 4: (0.0, 0.0)
};
test "verifica coordenadas de un punto" {
// Comprobamos que la coordenada Y del segundo punto es 23.6
try expect(puntos[1][1] == 23.6);
}
En este ejemplo verificamos el valor de la coordenada Y del segundo punto. El primer índice [1]
selecciona el segundo punto del array, y el segundo índice [1]
selecciona el segundo valor de ese punto (la coordenada Y).
Operaciones comunes con arrays
Iteración sobre elementos
La forma más común de procesar todos los elementos de un array es mediante un bucle for
:
// Iteración básica
for (array) |valor| {
// Código que utiliza 'valor'
}
// Iteración con índice
for (array, 0..) |valor, indice| {
// Código que utiliza 'valor' e 'indice'
}
Modificación de elementos durante la iteración
Para modificar los elementos de un array durante la iteración, necesitamos utilizar punteros:
for (&array) |*puntero| {
puntero.* += 1; // Incrementa el valor
}
Concatenación de arrays
Zig permite concatenar arrays en tiempo de compilación utilizando el operador ++
:
const parte1 = [_]i32{ 1, 2 };
const parte2 = [_]i32{ 3, 4 };
const combinado = parte1 ++ parte2; // Resulta en [1, 2, 3, 4]
Arrays versus slices
Es importante distinguir entre arrays y slices en Zig:
- Arrays: Tienen un tamaño fijo conocido en tiempo de compilación.
- Slices: Son referencias a una sección de un array, con una longitud conocida en tiempo de ejecución.
Los slices se declaran como []T
(sin número específico) y se obtienen a partir de arrays:
const array = [_]i32{ 1, 2, 3, 4, 5 };
const slice = array[1..4]; // Slice que contiene [2, 3, 4]
Conclusión
Los arrays en Zig son estructuras poderosas que nos permiten almacenar y manipular colecciones de datos del mismo tipo. Su sintaxis clara y su comportamiento predecible los hacen ideales para muchas aplicaciones, desde el manejo de texto hasta la representación de datos multidimensionales.
Los conceptos clave a recordar son:
- Los arrays tienen un tamaño fijo definido en tiempo de compilación.
- Se pueden declarar con tamaño explícito
[N]T
o inferido[_]T{...}
. - Se puede acceder a sus elementos mediante índices comenzando en 0.
- Los arrays multidimensionales permiten representar datos tabulares o espaciales.
- Zig proporciona operaciones útiles como iteración, modificación y concatenación de arrays.
Dominar el uso de arrays es fundamental para programar eficientemente en Zig, especialmente cuando necesitamos estructuras de datos con comportamiento predecible y rendimiento óptimo.