void em Zig — O que é e Como Usar

void em Zig — O que é e Como Usar

Definição

void é o tipo em Zig que representa ausência de valor. Ele ocupa zero bytes de memória e é usado principalmente como tipo de retorno de funções que não produzem resultado. Diferente de C, onde void é especial e não pode ser usado como valor, em Zig void é um tipo de primeira classe — pode ser atribuído a variáveis, usado em genéricos e armazenado em structs.

O valor literal de void é {}.

Por que void Importa

  1. Retorno de funções: Indica que uma função executa efeito colateral sem produzir valor.
  2. Genéricos: Permite criar contêineres onde o “valor” é ignorado (ex: HashSet usando HashMap com valor void).
  3. Otimização de memória: Campos void em structs não ocupam espaço.
  4. Consistência do sistema de tipos: Todo tipo em Zig pode ser usado uniformemente, incluindo void.

Exemplo Prático

Função com Retorno void

const std = @import("std");

fn saudar(nome: []const u8) void {
    std.debug.print("Olá, {s}!\n", .{nome});
    // Sem return explícito — retorna void implicitamente
}

fn processar(dados: []u8) void {
    for (dados) |*byte| {
        byte.* = byte.* +% 1; // incrementa cada byte
    }
    return; // return explícito de void (opcional)
}

pub fn main() void {
    saudar("Zig Brasil");

    var buffer = [_]u8{ 1, 2, 3 };
    processar(&buffer);
    std.debug.print("{any}\n", .{buffer}); // { 2, 3, 4 }
}

HashSet com void como Valor

const std = @import("std");

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

    // HashMap com valor void funciona como um Set
    var conjunto = std.AutoHashMap([]const u8, void).init(allocator);
    defer conjunto.deinit();

    try conjunto.put("zig", {});
    try conjunto.put("rust", {});
    try conjunto.put("go", {});

    // Verificar pertencimento
    const tem_zig = conjunto.contains("zig");
    std.debug.print("Tem zig: {}\n", .{tem_zig}); // true
}

void em Tipos Genéricos

const std = @import("std");

fn Wrapper(comptime T: type) type {
    return struct {
        valor: T,

        pub fn init(v: T) @This() {
            return .{ .valor = v };
        }

        pub fn temValor() bool {
            return T != void;
        }
    };
}

pub fn main() void {
    const com_valor = Wrapper(u32).init(42);
    const sem_valor = Wrapper(void).init({});

    std.debug.print("Com valor: {}\n", .{Wrapper(u32).temValor()});  // true
    std.debug.print("Sem valor: {}\n", .{Wrapper(void).temValor()}); // false
    _ = com_valor;
    _ = sem_valor;
}

void vs noreturn

TipoSignificadoExemplo
voidRetorna, mas sem valor útilfn processar() void
noreturnNunca retornafn sair() noreturn

Armadilhas Comuns

  • void vs noreturn: void retorna normalmente (sem valor); noreturn indica que a função nunca retorna (ex: @panic, loop infinito, std.process.exit).
  • Literal void: O valor de void é {}, não null. null é para optionals.
  • Comparação: Dois valores void são sempre iguais ({} == {} é true).
  • Em error unions: !void significa “pode retornar erro ou void”. É o tipo de retorno mais comum para funções que podem falhar sem produzir resultado.

Termos Relacionados

  • noreturn — Tipo para funções que nunca retornam
  • Optional — Tipo que pode ser nulo (diferente de void)
  • Error Union!void para funções que podem falhar
  • Struct — Campos void ocupam zero bytes

Tutoriais Relacionados

Continue aprendendo Zig

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