std.ArrayList — Array Dinâmico
O std.ArrayList é a estrutura de dados de array dinâmico da biblioteca padrão do Zig. Ele funciona como um vetor que cresce automaticamente conforme novos elementos são adicionados, gerenciando a alocação de memória de forma eficiente com crescimento exponencial. É o equivalente ao std::vector do C++ ou ao Vec do Rust.
Visão Geral
const std = @import("std");
const ArrayList = std.ArrayList;
O ArrayList é um tipo genérico parametrizado pelo tipo dos elementos. Internamente, ele mantém um ponteiro para um bloco de memória contígua, um comprimento (número de elementos inseridos) e uma capacidade (espaço total alocado).
Tipo e Assinatura
pub fn ArrayList(comptime T: type) type
O tipo retornado oferece os campos e métodos principais:
items— Slice[]Tdos elementos atuaiscapacity— Número total de posições alocadasallocator— O alocador usado para gerenciar memória
Funções Principais
Criação e Destruição
// Cria um ArrayList vazio
pub fn init(allocator: Allocator) ArrayList(T)
// Cria com capacidade inicial pré-alocada
pub fn initCapacity(allocator: Allocator, num: usize) Allocator.Error!ArrayList(T)
// Libera toda a memória
pub fn deinit(self: *ArrayList(T)) void
Adição de Elementos
// Adiciona um elemento ao final
pub fn append(self: *ArrayList(T), item: T) Allocator.Error!void
// Adiciona um slice inteiro ao final
pub fn appendSlice(self: *ArrayList(T), items: []const T) Allocator.Error!void
// Insere em posição específica, deslocando elementos
pub fn insert(self: *ArrayList(T), index: usize, item: T) Allocator.Error!void
Remoção de Elementos
// Remove e retorna o último elemento
pub fn pop(self: *ArrayList(T)) T
// Remove e retorna o último, ou null se vazio
pub fn popOrNull(self: *ArrayList(T)) ?T
// Remove elemento em índice específico (preserva ordem)
pub fn orderedRemove(self: *ArrayList(T), index: usize) T
// Remove por troca com último (não preserva ordem, O(1))
pub fn swapRemove(self: *ArrayList(T), index: usize) T
Redimensionamento
// Redimensiona para n elementos
pub fn resize(self: *ArrayList(T), new_len: usize) Allocator.Error!void
// Garante capacidade mínima sem alterar comprimento
pub fn ensureTotalCapacity(self: *ArrayList(T), new_capacity: usize) Allocator.Error!void
// Libera capacidade não utilizada
pub fn shrinkAndFree(self: *ArrayList(T), new_len: usize) void
// Limpa todos os elementos sem liberar memória
pub fn clearRetainingCapacity(self: *ArrayList(T)) void
// Limpa e libera memória
pub fn clearAndFree(self: *ArrayList(T)) void
Exemplo 1: Uso Básico — Construindo uma Lista
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Cria um ArrayList de inteiros
var lista = std.ArrayList(i32).init(allocator);
defer lista.deinit();
// Adiciona elementos
try lista.append(10);
try lista.append(20);
try lista.append(30);
try lista.appendSlice(&[_]i32{ 40, 50, 60 });
// Acessa os elementos via slice
const stdout = std.io.getStdOut().writer();
try stdout.print("Elementos: ", .{});
for (lista.items) |item| {
try stdout.print("{d} ", .{item});
}
try stdout.print("\n", .{});
try stdout.print("Comprimento: {d}, Capacidade: {d}\n", .{
lista.items.len,
lista.capacity,
});
// Remove o último
const ultimo = lista.pop();
try stdout.print("Removido: {d}\n", .{ultimo});
}
Exemplo 2: Filtragem e Transformação
const std = @import("std");
fn filtrarPares(lista: []const i32, allocator: std.mem.Allocator) !std.ArrayList(i32) {
var resultado = std.ArrayList(i32).init(allocator);
for (lista) |valor| {
if (@mod(valor, 2) == 0) {
try resultado.append(valor);
}
}
return resultado;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const dados = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var pares = try filtrarPares(&dados, allocator);
defer pares.deinit();
const stdout = std.io.getStdOut().writer();
try stdout.print("Números pares: ", .{});
for (pares.items) |v| {
try stdout.print("{d} ", .{v});
}
try stdout.print("\n", .{}); // Saída: 2 4 6 8 10
}
Exemplo 3: ArrayList como Buffer de Escrita
O ArrayList(u8) pode ser usado como um writer dinâmico para construir strings:
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const writer = buf.writer();
try writer.print("Nome: {s}, Idade: {d}\n", .{ "Ana", 30 });
try writer.print("Cidade: {s}\n", .{"São Paulo"});
// O conteúdo está disponível como string
const resultado = buf.items;
const stdout = std.io.getStdOut().writer();
try stdout.writeAll(resultado);
}
Padrões Comuns
Converter para Slice Owned
Use toOwnedSlice para obter o slice e transferir a propriedade da memória:
var lista = std.ArrayList(u8).init(allocator);
try lista.appendSlice("dados importantes");
const slice = try lista.toOwnedSlice();
defer allocator.free(slice);
// lista foi esvaziada; slice contém os dados
Ordenar Elementos
var lista = std.ArrayList(i32).init(allocator);
// ... adicionar elementos ...
std.mem.sort(i32, lista.items, {}, std.sort.asc(i32));
Módulos Relacionados
- std.mem.Allocator — Interface de alocação de memória
- std.heap — Implementações de alocadores
- std.BoundedArray — Array de tamanho fixo sem alocação
- std.MultiArrayList — Array de estruturas em layout SoA
- std.LinkedList — Lista encadeada