Struct em Zig — O que é e Como Usar

Struct em Zig — O que é e Como Usar

Definição

Uma struct (estrutura) em Zig é um tipo composto que agrupa campos nomeados de diferentes tipos em uma única unidade. Structs são o bloco fundamental para organização de dados em Zig — desempenham o papel que classes têm em linguagens orientadas a objeto, mas sem herança. Em vez disso, Zig favorece composição e interfaces via comptime.

Por que Structs Importam

  1. Organização de dados: Agrupam dados relacionados com nomes significativos.
  2. Métodos: Podem conter funções associadas, encapsulando comportamento.
  3. Valores default: Campos podem ter valores padrão, simplificando a criação.
  4. Genéricos: Structs podem ser geradas em comptime, criando tipos genéricos.

Exemplo Prático

Struct Básica

const std = @import("std");

const Ponto = struct {
    x: f64,
    y: f64,

    pub fn distancia(self: Ponto, outro: Ponto) f64 {
        const dx = self.x - outro.x;
        const dy = self.y - outro.y;
        return @sqrt(dx * dx + dy * dy);
    }

    pub fn origem() Ponto {
        return .{ .x = 0, .y = 0 };
    }
};

pub fn main() void {
    const a = Ponto{ .x = 3.0, .y = 4.0 };
    const b = Ponto.origem();

    std.debug.print("Distância: {d:.2}\n", .{a.distancia(b)}); // 5.00
}

Valores Default

const Config = struct {
    porta: u16 = 8080,
    host: []const u8 = "localhost",
    max_conexoes: u32 = 100,
    debug: bool = false,
};

pub fn main() void {
    // Apenas os campos que diferem do padrão
    const config = Config{
        .porta = 3000,
        .debug = true,
    };
    std.debug.print("Porta: {}, Debug: {}\n", .{ config.porta, config.debug });
}

Struct Genérica com Comptime

fn Pilha(comptime T: type) type {
    return struct {
        items: []T,
        topo: usize,
        allocator: std.mem.Allocator,

        const Self = @This();

        pub fn init(allocator: std.mem.Allocator, capacidade: usize) !Self {
            return Self{
                .items = try allocator.alloc(T, capacidade),
                .topo = 0,
                .allocator = allocator,
            };
        }

        pub fn deinit(self: *Self) void {
            self.allocator.free(self.items);
        }

        pub fn push(self: *Self, valor: T) !void {
            if (self.topo >= self.items.len) return error.PilhaCheia;
            self.items[self.topo] = valor;
            self.topo += 1;
        }

        pub fn pop(self: *Self) ?T {
            if (self.topo == 0) return null;
            self.topo -= 1;
            return self.items[self.topo];
        }
    };
}

Struct Anônima e Tupla

// Struct anônima (usada como literal)
const ponto = .{ .x = 10, .y = 20 };

// Tupla (struct anônima com campos indexados)
const tupla = .{ @as(u32, 42), "texto", true };
std.debug.print("Valor: {}\n", .{tupla[0]}); // 42

Tipos de Struct

TipoSintaxeCaracterística
Normalstruct { }Layout definido pelo compilador
Externextern struct { }Layout compatível com C ABI
Packedpacked struct { }Sem padding, campos bit a bit

Armadilhas Comuns

  • Esquecer o self: Métodos de instância recebem self como primeiro parâmetro. Métodos “estáticos” não recebem.
  • Mutabilidade: Para modificar campos, o parâmetro deve ser *Self (ponteiro mutável), não Self (cópia).
  • Ordem de inicialização: Todos os campos sem valor default devem ser inicializados. O compilador emite erro se algum for esquecido.
  • Confundir tipos de struct: struct, extern struct e packed struct têm layouts de memória diferentes. Escolha o correto para cada uso.

Termos Relacionados

Tutoriais Relacionados

Continue aprendendo Zig

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