Array Estático em Zig — Implementação Completa
O array estático é a estrutura de dados mais fundamental: uma sequência contígua de elementos com tamanho definido em tempo de compilação. Em Zig, arrays estáticos são cidadãos de primeira classe com excelente suporte da linguagem.
Conceito
Um array estático armazena N elementos do mesmo tipo em posições contíguas de memória. O tamanho é imutável após a criação.
Visualização
Array: [5]i32 = {10, 20, 30, 40, 50}
Memória:
Índice: 0 1 2 3 4
+-----+-----+-----+-----+-----+
Valor: | 10 | 20 | 30 | 40 | 50 |
+-----+-----+-----+-----+-----+
Endereço: 0x00 0x04 0x08 0x0C 0x10
Acesso direto: arr[2] = 30 → O(1)
Slice (referência a subseção):
arr[1..4] → {20, 30, 40} (não copia!)
Implementação em Zig
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// ==================== Criação ====================
// Array com valores explícitos
const numeros = [5]i32{ 10, 20, 30, 40, 50 };
// Array com inferência de tamanho
const letras = [_]u8{ 'Z', 'i', 'g' };
// Array inicializado com valor padrão
var zeros: [10]i32 = .{0} ** 10;
// Array inicializado com sentinela
const preenchido: [5]u8 = .{0xFF} ** 5;
// Array em comptime
const quadrados = comptime blk: {
var arr: [10]i32 = undefined;
for (0..10) |i| {
arr[i] = @intCast(i * i);
}
break :blk arr;
};
// ==================== Acesso ====================
try stdout.print("numeros[2] = {d}\n", .{numeros[2]});
try stdout.print("letras = {s}\n", .{&letras});
try stdout.print("quadrados = ", .{});
for (quadrados) |q| try stdout.print("{d} ", .{q});
try stdout.print("\n", .{});
// ==================== Slicing ====================
const slice = numeros[1..4]; // {20, 30, 40}
try stdout.print("numeros[1..4] = ", .{});
for (slice) |s| try stdout.print("{d} ", .{s});
try stdout.print("\n", .{});
// ==================== Iteração ====================
// Com valor
for (numeros) |n| {
_ = n;
}
// Com índice
for (numeros, 0..) |n, i| {
try stdout.print("numeros[{d}] = {d}\n", .{ i, n });
}
// ==================== Modificação ====================
zeros[3] = 42;
try stdout.print("zeros[3] = {d}\n", .{zeros[3]});
// ==================== Comparação ====================
const a = [_]i32{ 1, 2, 3 };
const b = [_]i32{ 1, 2, 3 };
const c = [_]i32{ 1, 2, 4 };
try stdout.print("a == b? {}\n", .{std.mem.eql(i32, &a, &b)});
try stdout.print("a == c? {}\n", .{std.mem.eql(i32, &a, &c)});
// ==================== Funções com arrays ====================
const soma = somarArray(&numeros);
try stdout.print("Soma: {d}\n", .{soma});
const encontrado = buscarLinear(&numeros, 30);
try stdout.print("30 no índice: {?d}\n", .{encontrado});
_ = preenchido;
}
/// Soma todos os elementos.
fn somarArray(arr: []const i32) i64 {
var soma: i64 = 0;
for (arr) |n| soma += n;
return soma;
}
/// Busca linear retornando o índice.
fn buscarLinear(arr: []const i32, alvo: i32) ?usize {
for (arr, 0..) |n, i| {
if (n == alvo) return i;
}
return null;
}
/// Array genérico em comptime com transformação.
fn mapear(comptime T: type, comptime n: usize, arr: [n]T, comptime f: fn (T) T) [n]T {
var resultado: [n]T = undefined;
for (arr, 0..) |val, i| {
resultado[i] = f(val);
}
return resultado;
}
Análise de Complexidade
| Operação | Tempo | Espaço |
|---|---|---|
| Acesso por índice | O(1) | - |
| Busca | O(n) | O(1) |
| Modificação | O(1) | - |
| Iteração | O(n) | O(1) |
| Slice | O(1) | O(1) — referência |
Características em Zig
- Tamanho em comptime: o compilador conhece o tamanho
- Sem overhead: nenhum custo extra comparado a C
- Bounds checking: verificação de limites em modo debug
- Coerção para slice: arrays se convertem automaticamente em slices
Quando Usar
- Tamanho conhecido em tempo de compilação
- Dados que não mudam de tamanho
- Buffers de tamanho fixo (parsing, I/O)
- Tabelas de lookup pré-computadas
Recursos Relacionados
- Array Dinâmico — Para tamanho variável
- Pilha — Pode ser implementada com array
- Ring Buffer — Buffer circular com array fixo
- BitSet — Array de bits compacto