---
title: "Union em Zig — O que é e Como Usar"
url: "https://ziglang.com.br/glossario/union-em-zig-o-que-%C3%A9-e-como-usar/"
markdown_url: "https://ziglang.com.br/glossario/union-em-zig-o-que-%C3%A9-e-como-usar.MD"
description: "Entenda unions em Zig: tipos que armazenam um valor dentre vários possíveis no mesmo espaço de memória. Diferenças para tagged unions. Guia pt-BR."
date: "2026-02-21"
author: "Zig Brasil"
---

# Union em Zig — O que é e Como Usar

Entenda unions em Zig: tipos que armazenam um valor dentre vários possíveis no mesmo espaço de memória. Diferenças para tagged unions. Guia pt-BR.


# Union em Zig — O que é e Como Usar

## Definição

Uma **union** em Zig é um tipo que pode armazenar **um único valor dentre vários campos possíveis**, todos compartilhando o mesmo espaço de memória. O tamanho da union é igual ao tamanho do seu maior campo. Existem três variantes de unions em Zig:

- **`union(enum)`**: Tagged union — segura, com tag automática (ver [Tagged Union](/glossario/tagged-union/))
- **`extern union`**: Compatível com layout C, sem tag
- **`union`** (bare): Sem tag, com verificação em modo Debug

A forma mais comum e recomendada é a tagged union (`union(enum)`). Bare unions e extern unions existem para interoperabilidade e otimizações específicas.

## Por que Unions Importam

1. **Economia de memória**: Todos os campos compartilham o mesmo espaço — útil quando só um estará ativo por vez.
2. **Interoperabilidade com C**: `extern union` permite usar unions de APIs C.
3. **Modelagem de tipos variantes**: Representam dados que podem ter formas diferentes.
4. **Pattern matching**: Tagged unions combinam com `switch` para despacho seguro.

## Exemplo Prático

### Bare Union (Sem Tag)

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

const Valor = union {
    inteiro: i64,
    float: f64,
    ponteiro: *anyopaque,
};

pub fn main() void {
    var v = Valor{ .inteiro = 42 };

    // Em modo Debug, acessar o campo errado causa panic
    std.debug.print("Inteiro: {}\n", .{v.inteiro});

    // Reatribuir para outro campo
    v = Valor{ .float = 3.14 };
    std.debug.print("Float: {d}\n", .{v.float});
}
```

### Extern Union (Compatível com C)

```zig
const c = @cImport(@cInclude("sys/socket.h"));

// Representa a union sockaddr_in do C
const EnderecoIP = extern union {
    v4: [4]u8,
    v4_int: u32,
};

pub fn main() void {
    const addr = EnderecoIP{ .v4 = .{ 192, 168, 1, 1 } };
    // Acessar como inteiro (reinterpretação de bits)
    std.debug.print("Como u32: {}\n", .{addr.v4_int});
}
```

### Tagged Union (Recomendada)

```zig
const Resultado = union(enum) {
    sucesso: i32,
    erro_io: std.posix.E,
    erro_parse: struct { linha: u32, coluna: u32 },
    nenhum: void,

    pub fn ehSucesso(self: Resultado) bool {
        return self == .sucesso;
    }
};

fn processar() Resultado {
    return .{ .sucesso = 42 };
}

pub fn main() void {
    const r = processar();
    switch (r) {
        .sucesso => |val| std.debug.print("OK: {}\n", .{val}),
        .erro_io => |e| std.debug.print("Erro IO: {}\n", .{e}),
        .erro_parse => |e| std.debug.print("Parse erro: {}:{}\n", .{ e.linha, e.coluna }),
        .nenhum => std.debug.print("Nada\n", .{}),
    }
}
```

## Comparação de Tipos de Union

| Tipo | Tag | Segurança | Uso |
|------|-----|-----------|-----|
| `union(enum)` | Automática | Total | Uso geral |
| `union` (bare) | Nenhuma | Debug only | Otimização |
| `extern union` | Nenhuma | Nenhuma | Interop C |

## Quando Usar Cada Tipo de Union

- **`union(enum)`**: Na grande maioria dos casos. Oferece segurança total com switch exhaustivo e verificação de campo ativo em runtime.
- **`extern union`**: Apenas ao fazer interop com structs C que contém unions. O layout deve ser exatamente o mesmo definido pelo C ABI.
- **`union` (bare)**: Raramente. Pode ser útil em otimizações muito específicas onde você garante externamente qual campo está ativo, mas o custo de bugs é alto.

## Casos de Uso Reais

Tagged unions são excelentes para modelar resultados com contexto variável:

```zig
const Evento = union(enum) {
    tecla_pressionada: u8,
    mouse_movido: struct { x: i32, y: i32 },
    redimensionar: struct { largura: u32, altura: u32 },
    fechar: void,
};

fn processarEvento(ev: Evento) void {
    switch (ev) {
        .tecla_pressionada => |key| {
            std.debug.print("Tecla: {c}\n", .{key});
        },
        .mouse_movido => |pos| {
            std.debug.print("Mouse: {}x{}\n", .{ pos.x, pos.y });
        },
        .redimensionar => |dim| {
            std.debug.print("Novo tamanho: {}x{}\n", .{ dim.largura, dim.altura });
        },
        .fechar => std.debug.print("Fechando\n", .{}),
    }
}
```

Neste exemplo, o compilador garante que todos os casos são tratados. Adicionar um novo campo à union sem atualizar o switch resulta em **erro de compilação**.

## Armadilhas Comuns

- **Acessar campo inativo em bare union**: Em modo Release, não há verificação — comportamento indefinido. Prefira tagged unions.
- **Esquecer de usar `union(enum)`**: Se você não precisa de interop com C, sempre use tagged unions para segurança.
- **Assumir layout**: O layout de `union` (bare) não é garantido. Use `extern union` se precisar de layout compatível com C.
- **Tamanho inesperado**: O tamanho é o do maior campo + padding. Uma tagged union também inclui o tamanho da tag enum.

## Termos Relacionados

- [Tagged Union](/glossario/tagged-union/) — Union com discriminante automático
- [Enum](/glossario/enum/) — Enumerações usadas como tags
- [Struct](/glossario/struct/) — Tipos estruturados
- [Packed Struct](/glossario/packed-struct/) — Structs com layout exato

## Tutoriais Relacionados

- [Structs, Enums e Unions em Zig](/tutoriais/structs-enums-unions-zig/)
- [Zig e C — Interoperabilidade](/tutoriais/zig-c-interoperabilidade/)
- [Introdução ao Zig](/tutoriais/introducao-ao-zig/)
