---
title: "std.MultiArrayList em Zig — Referência e Exemplos"
url: "https://ziglang.com.br/stdlib/std.multiarraylist-em-zig-refer%C3%AAncia-e-exemplos/"
markdown_url: "https://ziglang.com.br/stdlib/std.multiarraylist-em-zig-refer%C3%AAncia-e-exemplos.MD"
description: "Guia completo do std.MultiArrayList em Zig em português. Estrutura de Arrays (SoA) para alto desempenho com cache e exemplos práticos."
date: "2026-02-21"
author: "Zig Brasil"
---

# std.MultiArrayList em Zig — Referência e Exemplos

Guia completo do std.MultiArrayList em Zig em português. Estrutura de Arrays (SoA) para alto desempenho com cache e exemplos práticos.


# std.MultiArrayList — Estrutura de Arrays (SoA)

O `std.MultiArrayList` implementa o padrão Structure of Arrays (SoA), onde uma coleção de structs é armazenada como arrays separados para cada campo, em vez de um array de structs (AoS). Este layout melhora drasticamente o desempenho de cache quando o código acessa apenas alguns campos de cada vez, sendo uma peça central do design orientado a dados (*data-oriented design*) que o Zig promove.

## Visão Geral

```zig
const std = @import("std");
const MultiArrayList = std.MultiArrayList;
```

### Por que SoA?

Considere uma struct `Particula` com posição, velocidade e cor. Se você iterar sobre todas as partículas atualizando apenas a posição, com AoS (Array of Structs) cada acesso carrega para o cache os campos de velocidade e cor desnecessariamente. Com SoA, os campos de posição ficam contíguos na memória, maximizando a utilização do cache.

### Tipo e Assinatura

```zig
pub fn MultiArrayList(comptime T: type) type
```

O tipo `T` deve ser uma struct. O `MultiArrayList` gera automaticamente arrays separados para cada campo.

## Funções Principais

### Criação e Destruição

```zig
// Cria lista vazia
pub fn init() MultiArrayList(T) // não requer allocator no init

// Libera memória
pub fn deinit(self: *Self, allocator: Allocator) void
```

### Inserção e Remoção

```zig
// Adiciona um elemento (struct completa)
pub fn append(self: *Self, allocator: Allocator, elem: T) Allocator.Error!void

// Remove o último elemento
pub fn pop(self: *Self) void

// Remove em índice (preserva ordem)
pub fn orderedRemove(self: *Self, index: usize) void

// Remove por troca (O(1))
pub fn swapRemove(self: *Self, index: usize) void
```

### Acesso aos Dados

```zig
// Acesso ao slice de um campo específico
pub fn items(self: Self, comptime field: FieldEnum) []FieldType

// Número de elementos
pub fn len(self: Self) usize

// Acessa um elemento completo como struct
pub fn get(self: Self, index: usize) T

// Define um elemento completo
pub fn set(self: *Self, index: usize, elem: T) void
```

## Exemplo 1: Sistema de Partículas

```zig
const std = @import("std");

const Particula = struct {
    x: f32,
    y: f32,
    vx: f32,
    vy: f32,
    vida: f32,
    ativa: bool,
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var particulas = std.MultiArrayList(Particula){};
    defer particulas.deinit(allocator);

    // Cria partículas
    for (0..5) |i| {
        const fi: f32 = @floatFromInt(i);
        try particulas.append(allocator, .{
            .x = fi * 10.0,
            .y = 0.0,
            .vx = 1.0,
            .vy = fi * 0.5,
            .vida = 100.0,
            .ativa = true,
        });
    }

    // Atualiza apenas posições — acesso SoA eficiente
    const xs = particulas.items(.x);
    const ys = particulas.items(.y);
    const vxs = particulas.items(.vx);
    const vys = particulas.items(.vy);

    for (xs, ys, vxs, vys) |*x, *y, vx, vy| {
        x.* += vx;
        y.* += vy;
    }

    // Exibe resultados
    const stdout = std.io.getStdOut().writer();
    try stdout.writeAll("Partículas após atualização:\n");
    for (0..particulas.len) |i| {
        const p = particulas.get(i);
        try stdout.print("  P{d}: pos=({d:.1}, {d:.1}) vida={d:.0}\n", .{
            i, p.x, p.y, p.vida,
        });
    }
}
```

## Exemplo 2: Entidades de Jogo

```zig
const std = @import("std");

const Entidade = struct {
    nome_id: u32,
    pos_x: f32,
    pos_y: f32,
    saude: i32,
    dano: i32,
    tipo: Tipo,

    const Tipo = enum { jogador, inimigo, npc };
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var entidades = std.MultiArrayList(Entidade){};
    defer entidades.deinit(allocator);

    try entidades.append(allocator, .{
        .nome_id = 1, .pos_x = 0, .pos_y = 0,
        .saude = 100, .dano = 10, .tipo = .jogador,
    });
    try entidades.append(allocator, .{
        .nome_id = 2, .pos_x = 5, .pos_y = 3,
        .saude = 50, .dano = 15, .tipo = .inimigo,
    });
    try entidades.append(allocator, .{
        .nome_id = 3, .pos_x = -2, .pos_y = 7,
        .saude = 30, .dano = 20, .tipo = .inimigo,
    });

    // Aplica dano a todos os inimigos (acessa apenas tipo e saude)
    const tipos = entidades.items(.tipo);
    const saudes = entidades.items(.saude);

    for (tipos, saudes) |tipo, *saude| {
        if (tipo == .inimigo) {
            saude.* -= 10;
        }
    }

    const stdout = std.io.getStdOut().writer();
    try stdout.writeAll("Estado das entidades:\n");
    for (0..entidades.len) |i| {
        const e = entidades.get(i);
        try stdout.print("  ID={d} tipo={s} saude={d}\n", .{
            e.nome_id, @tagName(e.tipo), e.saude,
        });
    }
}
```

## Exemplo 3: Benchmark SoA vs AoS Conceitual

```zig
const std = @import("std");

const Dados = struct {
    valor_quente: u64,    // campo acessado frequentemente
    payload_frio: [56]u8, // campo raramente acessado (56 bytes)
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var soa = std.MultiArrayList(Dados){};
    defer soa.deinit(allocator);

    // Preenche com dados
    for (0..1000) |i| {
        try soa.append(allocator, .{
            .valor_quente = i,
            .payload_frio = [_]u8{0} ** 56,
        });
    }

    // Soma apenas o campo quente — SoA carrega apenas 8KB (1000 * 8 bytes)
    // Em AoS, carregaria 64KB (1000 * 64 bytes) para o cache
    var soma: u64 = 0;
    for (soa.items(.valor_quente)) |v| {
        soma += v;
    }

    const stdout = std.io.getStdOut().writer();
    try stdout.print("Soma dos valores quentes: {d}\n", .{soma});
    try stdout.print("Elementos: {d}\n", .{soa.len});
}
```

## Quando Usar MultiArrayList

- **Iteração sobre poucos campos**: Quando o loop acessa 1-2 campos de uma struct grande
- **Dados numéricos em massa**: Simulações físicas, gráficos, processamento de sinais
- **SIMD**: O layout contíguo facilita vetorização automática pelo compilador
- **Structs com campos grandes**: Quando structs têm campos raramente usados juntos

## Módulos Relacionados

- [std.ArrayList](/stdlib/std-array-list/) — Array dinâmico tradicional (AoS)
- [std.BoundedArray](/stdlib/std-bounded-array/) — Array de tamanho fixo
- [std.mem.Allocator](/stdlib/std-mem-allocator/) — Interface de alocação

## Tutoriais e Receitas Relacionados

- [Tutorial: Design Orientado a Dados em Zig](/tutoriais/data-oriented-design/)
- [Receita: Otimização de Performance](/receitas/otimizacao-performance/)
