Slice em Zig — O que é e Como Usar

Slice em Zig — O que é e Como Usar

Definição

Um Slice em Zig é uma referência a uma sequência contígua de elementos na memória, representada pelo tipo []T. Internamente, um slice é composto por dois campos: um ponteiro para o início dos dados e um comprimento (length). Slices não possuem os dados — eles apenas apontam para dados que existem em outro lugar (um array, memória alocada no heap, etc.).

Slices são o tipo mais comum para trabalhar com sequências de dados em Zig, substituindo o padrão de C de “ponteiro + tamanho separado”.

Por que Slices Importam

  1. Segurança: Carregam o tamanho junto do ponteiro, permitindo verificação de limites.
  2. Ergonomia: Suportam sintaxe de indexação (slice[i]), iteração (for) e fatiamento (slice[a..b]).
  3. Interoperabilidade: Podem ser criados a partir de arrays, ponteiros ou memória alocada.
  4. String literals: Em Zig, strings são []const u8 — ou seja, slices de bytes.

Exemplo Prático

Criando Slices

const std = @import("std");

pub fn main() void {
    // A partir de um array
    var array = [_]u32{ 10, 20, 30, 40, 50 };
    const slice: []u32 = array[1..4]; // [20, 30, 40]

    std.debug.print("Tamanho: {}\n", .{slice.len}); // 3
    std.debug.print("Primeiro: {}\n", .{slice[0]});  // 20

    // Iteração
    for (slice) |valor| {
        std.debug.print("{} ", .{valor});
    }
}

Slices como Parâmetros

fn soma(numeros: []const u32) u64 {
    var total: u64 = 0;
    for (numeros) |n| {
        total += n;
    }
    return total;
}

pub fn main() void {
    const array = [_]u32{ 1, 2, 3, 4, 5 };
    const resultado = soma(&array); // Array coerce para slice
    std.debug.print("Soma: {}\n", .{resultado}); // 15
}

Fatiamento (Slicing)

const texto: []const u8 = "Zig Brasil";

const zig = texto[0..3];     // "Zig"
const brasil = texto[4..10]; // "Brasil"
const tudo = texto[0..];     // "Zig Brasil" (até o fim)

Slice de Memória Alocada

fn criarBuffer(allocator: std.mem.Allocator, tamanho: usize) ![]u8 {
    const buffer = try allocator.alloc(u8, tamanho);
    @memset(buffer, 0); // Inicializa com zeros
    return buffer;
}

Tipos de Slice

TipoDescrição
[]TSlice mutável
[]const TSlice somente leitura
[:0]u8Slice terminado em sentinel (zero)
[*]TMany-pointer (sem tamanho conhecido)

Representação Interna

[]u32 é equivalente a:

struct {
    ptr: [*]u32,  // Ponteiro para o primeiro elemento
    len: usize,   // Número de elementos
}

Tamanho total: 2 * @sizeOf(usize) = 16 bytes em 64-bit

Boas Práticas

  • Prefira []const T em parâmetros: Se uma função não precisa modificar os dados, use []const T. Isso permite passar tanto slices mutáveis quanto imutáveis sem conversão.
  • Use &array para coerção: Um array [N]T pode ser passado como []T escrevendo &array. A coerção é automática.
  • Cuidado com lifetime: Um slice deve sobreviver no máximo tanto quanto os dados que aponta. Não retorne slices de arrays locais.
  • Prefira iteração com for: Em vez de for (0..slice.len) |i|, use for (slice) |elemento| quando o índice não é necessário.
  • Use std.mem para operações: std.mem.eql, std.mem.indexOf, std.mem.copy etc. operam sobre slices e cobrem os casos mais comuns.

Comparação com Outras Linguagens

LinguagemEquivalenteNotas
Cptr + len separadosSem encapsulamento
GosliceSimilar, mas com capacidade extra
Rust&[T]Idêntico em conceito
C++std::span<T> (C++20)Similar, mas opcional

A diferença em relação ao Go é que o slice de Zig não tem campo cap (capacidade) separado do len. Em Go, o capacity permite append sem realocação; em Zig, redimensionamento sempre passa pelo allocator explicitamente.

Armadilhas Comuns

  • Slice não possui os dados: Se o array original sair do escopo, o slice se torna um dangling pointer. Cuidado com slices de arrays locais retornados de funções.
  • Indexação fora dos limites: Acessar slice[slice.len] ou índices negativos causa panic em modo Debug/ReleaseSafe.
  • Confundir []T com [N]T: [N]T é um array de tamanho fixo (valor); []T é um slice (referência).
  • Modificar slice const: []const u8 não permite modificação. Tente []u8 se precisar alterar os dados.
  • Esquecer de liberar: Slices de memória alocada (allocator.alloc) devem ser liberados com allocator.free.

Termos Relacionados

Tutoriais Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.