← Volver al listado de tecnologías

Arrays y Slices en Zig

Por: Artiko
zigarraysslicesstrings

Arrays y Slices

Arrays Estáticos

Los arrays tienen tamaño fijo conocido en tiempo de compilación:

const std = @import("std");

pub fn main() void {
    // Array con tipo explícito
    const numeros: [5]i32 = [5]i32{ 1, 2, 3, 4, 5 };

    // Inferencia de tamaño
    const letras = [_]u8{ 'a', 'b', 'c' };

    // Array inicializado con valor
    const ceros = [_]i32{0} ** 10; // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    // Acceso por índice
    std.debug.print("Primero: {d}\n", .{numeros[0]});
    std.debug.print("Longitud: {d}\n", .{numeros.len});

    // Array de arrays (matriz)
    const matriz = [3][3]i32{
        [_]i32{ 1, 2, 3 },
        [_]i32{ 4, 5, 6 },
        [_]i32{ 7, 8, 9 },
    };
    std.debug.print("Centro: {d}\n", .{matriz[1][1]}); // 5
}

Slices

Los slices son vistas a arrays con longitud conocida en runtime:

const std = @import("std");

pub fn main() void {
    var array = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    // Slice del array completo
    const todo: []i32 = &array;

    // Slice parcial [inicio..fin)
    const medio = array[3..7]; // [4, 5, 6, 7]

    // Desde el inicio
    const primeros = array[0..3]; // [1, 2, 3]

    // Hasta el final
    const ultimos = array[7..]; // [8, 9, 10]

    // Modificar a través del slice
    todo[0] = 100;
    std.debug.print("Primer elemento: {d}\n", .{array[0]}); // 100

    // Longitud del slice
    std.debug.print("Longitud medio: {d}\n", .{medio.len}); // 4
}

Strings

En Zig, los strings son arrays de bytes ([]const u8):

const std = @import("std");

pub fn main() void {
    // String literal
    const saludo: []const u8 = "Hola mundo";

    // Longitud
    std.debug.print("Longitud: {d}\n", .{saludo.len});

    // Iterar caracteres
    for (saludo) |char| {
        std.debug.print("{c}", .{char});
    }

    // Comparación de strings
    const a = "hola";
    const b = "hola";
    const iguales = std.mem.eql(u8, a, b);
    std.debug.print("\nIguales: {}\n", .{iguales});

    // String multilínea
    const multi =
        \\Línea 1
        \\Línea 2
        \\Línea 3
    ;
    std.debug.print("{s}\n", .{multi});
}

Operaciones con Slices

const std = @import("std");
const mem = std.mem;

pub fn main() void {
    const texto = "Hola,Mundo,Zig";

    // Buscar substring
    if (mem.indexOf(u8, texto, "Mundo")) |pos| {
        std.debug.print("'Mundo' encontrado en: {d}\n", .{pos});
    }

    // Split
    var iter = mem.splitSequence(u8, texto, ",");
    while (iter.next()) |parte| {
        std.debug.print("Parte: {s}\n", .{parte});
    }

    // Starts/ends with
    std.debug.print("Empieza con 'Hola': {}\n", .{mem.startsWith(u8, texto, "Hola")});
    std.debug.print("Termina con 'Zig': {}\n", .{mem.endsWith(u8, texto, "Zig")});
}

Sentinel-Terminated Arrays

Arrays terminados con un valor especial (útil para interop con C):

const std = @import("std");

pub fn main() void {
    // String terminado en null (para C)
    const c_string: [:0]const u8 = "Hola C";

    // Longitud sin contar el terminador
    std.debug.print("Longitud: {d}\n", .{c_string.len}); // 6

    // Acceder al terminador
    std.debug.print("Terminador: {d}\n", .{c_string[c_string.len]}); // 0

    // Array terminado con valor custom
    const arr: [5:255]u8 = [_:255]u8{ 1, 2, 3, 4, 5 };
    std.debug.print("Sentinel: {d}\n", .{arr[5]}); // 255
}

Concatenación y Repetición

const std = @import("std");

pub fn main() void {
    // Concatenación en comptime
    const a = "Hola";
    const b = " mundo";
    const c = a ++ b; // "Hola mundo"

    // Repetición
    const repetido = "ab" ** 3; // "ababab"

    std.debug.print("{s}\n", .{c});
    std.debug.print("{s}\n", .{repetido});
}

Testing de Arrays y Slices

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

fn sumar(arr: []const i32) i32 {
    var total: i32 = 0;
    for (arr) |n| total += n;
    return total;
}

fn buscar(arr: []const i32, valor: i32) ?usize {
    for (arr, 0..) |elem, i| {
        if (elem == valor) return i;
    }
    return null;
}

fn invertir(arr: []i32) void {
    var izq: usize = 0;
    var der: usize = arr.len - 1;
    while (izq < der) {
        const temp = arr[izq];
        arr[izq] = arr[der];
        arr[der] = temp;
        izq += 1;
        der -= 1;
    }
}

fn contiene(haystack: []const u8, needle: []const u8) bool {
    return mem.indexOf(u8, haystack, needle) != null;
}

test "array básico" {
    const arr = [_]i32{ 1, 2, 3, 4, 5 };
    try testing.expectEqual(@as(usize, 5), arr.len);
    try testing.expectEqual(@as(i32, 1), arr[0]);
    try testing.expectEqual(@as(i32, 5), arr[4]);
}

test "slice de array" {
    const arr = [_]i32{ 10, 20, 30, 40, 50 };
    const slice = arr[1..4];

    try testing.expectEqual(@as(usize, 3), slice.len);
    try testing.expectEqual(@as(i32, 20), slice[0]);
    try testing.expectEqual(@as(i32, 40), slice[2]);
}

test "suma de array" {
    const arr = [_]i32{ 1, 2, 3, 4, 5 };
    try testing.expectEqual(@as(i32, 15), sumar(&arr));

    const vacio = [_]i32{};
    try testing.expectEqual(@as(i32, 0), sumar(&vacio));
}

test "búsqueda en array" {
    const arr = [_]i32{ 10, 20, 30, 40, 50 };

    try testing.expectEqual(@as(?usize, 2), buscar(&arr, 30));
    try testing.expectEqual(@as(?usize, 0), buscar(&arr, 10));
    try testing.expectEqual(@as(?usize, null), buscar(&arr, 99));
}

test "invertir array" {
    var arr = [_]i32{ 1, 2, 3, 4, 5 };
    invertir(&arr);

    try testing.expectEqual(@as(i32, 5), arr[0]);
    try testing.expectEqual(@as(i32, 4), arr[1]);
    try testing.expectEqual(@as(i32, 1), arr[4]);
}

test "comparación de strings" {
    try testing.expect(mem.eql(u8, "hola", "hola"));
    try testing.expect(!mem.eql(u8, "hola", "mundo"));
}

test "búsqueda en strings" {
    const texto = "Zig es genial";

    try testing.expect(contiene(texto, "es"));
    try testing.expect(contiene(texto, "genial"));
    try testing.expect(!contiene(texto, "malo"));
}

test "starts y ends with" {
    const texto = "archivo.zig";

    try testing.expect(mem.startsWith(u8, texto, "archivo"));
    try testing.expect(mem.endsWith(u8, texto, ".zig"));
    try testing.expect(!mem.startsWith(u8, texto, "otro"));
}

test "concatenación comptime" {
    const resultado = "Hello" ++ " " ++ "World";
    try testing.expectEqualStrings("Hello World", resultado);
}

Ejercicios

  1. Implementa una función que encuentre el elemento máximo de un array
  2. Crea una función que cuente las ocurrencias de un carácter en un string
  3. Implementa una función que verifique si un array es un palíndromo

Resumen