---
title: "Cheatsheet: Adapter em Zig"
url: "https://ziglang.com.br/padroes/cheatsheet-adapter-em-zig/"
markdown_url: "https://ziglang.com.br/padroes/cheatsheet-adapter-em-zig.MD"
description: "Design pattern Adapter implementado em Zig: adaptar interfaces incompatíveis para trabalharem juntas, wrapping de APIs C e unificação de interfaces. Guia completo em português."
date: "2026-02-21"
author: "Zig Brasil"
---

# Cheatsheet: Adapter em Zig

Design pattern Adapter implementado em Zig: adaptar interfaces incompatíveis para trabalharem juntas, wrapping de APIs C e unificação de interfaces. Guia completo em português.


# Adapter em Zig

O padrão Adapter permite que interfaces incompatíveis trabalhem juntas, convertendo a interface de uma struct em outra que o código cliente espera. Em Zig, esse padrão é muito usado para envolver APIs C em interfaces idiomáticas Zig, ou para unificar diferentes implementações sob uma interface comum.

## Quando Usar

- Wrapping de bibliotecas C para interface idiomática Zig
- Unificar diferentes fontes de dados sob mesma interface
- Converter entre formatos de dados incompatíveis
- Integrar bibliotecas de terceiros com API diferente da esperada

## Adapter para API C

```zig
const std = @import("std");
const c = @cImport(@cInclude("stdio.h"));

// API C retorna ponteiro ou NULL, usa errno
// Adapter converte para interface Zig com error unions

const ArquivoAdaptado = struct {
    handle: *c.FILE,

    const Erro = error{
        FalhaAoAbrir,
        FalhaAoLer,
        FalhaAoEscrever,
    };

    pub fn abrir(caminho: [:0]const u8, modo: [:0]const u8) Erro!ArquivoAdaptado {
        const handle = c.fopen(caminho.ptr, modo.ptr);
        if (handle == null) return error.FalhaAoAbrir;
        return .{ .handle = handle.? };
    }

    pub fn fechar(self: *ArquivoAdaptado) void {
        _ = c.fclose(self.handle);
    }

    pub fn escrever(self: *ArquivoAdaptado, dados: []const u8) Erro!usize {
        const escrito = c.fwrite(dados.ptr, 1, dados.len, self.handle);
        if (escrito == 0) return error.FalhaAoEscrever;
        return escrito;
    }

    pub fn ler(self: *ArquivoAdaptado, buffer: []u8) Erro!usize {
        const lido = c.fread(buffer.ptr, 1, buffer.len, self.handle);
        if (lido == 0 and c.ferror(self.handle) != 0) return error.FalhaAoLer;
        return lido;
    }
};

pub fn main() !void {
    var arquivo = try ArquivoAdaptado.abrir("/tmp/teste.txt", "w");
    defer arquivo.fechar();

    _ = try arquivo.escrever("Olá do adapter!\n");
}
```

## Adapter de Interface Genérica

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

// Interface comum
const FonteDados = struct {
    ptr: *anyopaque,
    lerFn: *const fn (*anyopaque, []u8) ?[]const u8,

    pub fn ler(self: FonteDados, buffer: []u8) ?[]const u8 {
        return self.lerFn(self.ptr, buffer);
    }
};

// Adaptar ArrayList para FonteDados
const ArrayListAdapter = struct {
    lista: *std.ArrayList([]const u8),
    indice: usize = 0,

    pub fn fonteDados(self: *ArrayListAdapter) FonteDados {
        return .{
            .ptr = @ptrCast(self),
            .lerFn = @ptrCast(&proximo),
        };
    }

    fn proximo(self: *ArrayListAdapter, buffer: []u8) ?[]const u8 {
        _ = buffer;
        if (self.indice >= self.lista.items.len) return null;
        const item = self.lista.items[self.indice];
        self.indice += 1;
        return item;
    }
};

// Adaptar slice estático para FonteDados
const SliceAdapter = struct {
    dados: []const []const u8,
    indice: usize = 0,

    pub fn fonteDados(self: *SliceAdapter) FonteDados {
        return .{
            .ptr = @ptrCast(self),
            .lerFn = @ptrCast(&proximo),
        };
    }

    fn proximo(self: *SliceAdapter, buffer: []u8) ?[]const u8 {
        _ = buffer;
        if (self.indice >= self.dados.len) return null;
        const item = self.dados[self.indice];
        self.indice += 1;
        return item;
    }
};

// Código cliente trabalha com FonteDados sem saber a origem
fn processarDados(fonte: FonteDados) void {
    var buf: [1024]u8 = undefined;
    while (fonte.ler(&buf)) |dado| {
        std.debug.print("Dado: {s}\n", .{dado});
    }
}
```

## Adapter com comptime para Múltiplos Backends

Uma técnica poderosa é usar `comptime` para criar adapters sem custo de runtime, resolvendo a implementação concreta em tempo de compilação:

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

fn StorageAdapter(comptime Backend: type) type {
    return struct {
        backend: Backend,

        pub fn salvar(self: *@This(), chave: []const u8, valor: []const u8) !void {
            // Verifica em comptime que o backend tem o método correto
            if (!@hasDecl(Backend, "write")) {
                @compileError("Backend deve implementar write(chave, valor)");
            }
            try self.backend.write(chave, valor);
        }

        pub fn carregar(self: *@This(), chave: []const u8) !?[]const u8 {
            return self.backend.read(chave);
        }
    };
}

// Backend em memória (para testes)
const MemBackend = struct {
    dados: std.StringHashMap([]const u8),

    pub fn write(self: *MemBackend, chave: []const u8, valor: []const u8) !void {
        try self.dados.put(chave, valor);
    }
    pub fn read(self: *MemBackend, chave: []const u8) !?[]const u8 {
        return self.dados.get(chave);
    }
};
```

Neste caso, o adapter é resolvido em `comptime` — o binário final contém apenas as chamadas diretas ao `MemBackend`, sem indireção via ponteiro de função.

## Considerações de Performance

- **Adapter para C via `@cImport`**: o overhead é praticamente zero — são chamadas diretas às funções C com conversão de tipos, não há alocação extra.
- **Adapter com `anyopaque` + ponteiro de função**: introduz uma indireção por chamada. Aceitável na maioria dos casos, mas evite no hot path de renderização ou parsing intenso.
- **Adapter comptime**: custo zero em runtime. O compilador resolve tudo estáticamentee pode inlinar as chamadas.
- Use `@ptrCast` com cuidado — certifique-se de que o alinhamento do ponteiro está correto. O compilador vai alertar sobre mismatches de alinhamento.

## Erros Comuns

**Esquecer de propagar o lifetime**: o adapter não deve viver mais que o objeto que wrapa. Se o adapter guarda um ponteiro para o objeto original, certifique-se de que o original não é destruído antes.

**Assinar o tipo errado em `@ptrCast`**: ao criar interfaces com `*anyopaque`, a função que recebe o ponteiro deve ter assinatura idêntica à que foi convertida. O compilador não consegue verificar isso em todos os casos.

**Não tratar todos os erros da API C**: APIs C frequentemente sinalizam erros via valores de retorno negativos, `errno`, ou ponteiros nulos. Adapters devem mapear *todos* esses casos para error unions Zig — nunca ignore um valor de retorno de função C.

## Perguntas Frequentes

**Qual é a diferença entre Adapter e Facade?**
O Adapter converte uma interface em outra que o cliente já espera — é um "tradutor". A Facade cria uma interface mais simples sobre um sistema complexo, sem necessariamente mudar a forma como o cliente se comunica.

**Devo criar um adapter para cada biblioteca C que uso?**
Para bibliotecas grandes (SQLite, OpenSSL, libcurl), vale criar um adapter idiomático completo. Para poucas funções de uma biblioteca auxiliar, um wrapper de função simples é suficiente e mais fácil de manter.

**Como testar um adapter para API C sem ter a biblioteca disponível?**
Crie um `MockBackend` que implementa a mesma interface que o adapter expõe, usando o padrão de comptime. Nos testes, injete o mock em vez do adapter real.

## Quando Evitar

- Quando as interfaces já são compatíveis
- Quando um simples wrapper de função resolve
- Se o adapter adiciona complexidade sem benefício claro
- Quando é possível modificar a interface original

## Veja Também

- [Facade](/padroes/facade/) — Simplificar interface complexa
- [Decorator](/padroes/decorator/) — Adicionar comportamento sem alterar interface
- [Interop com C](/cheatsheets/c-interop/) — Wrapping de APIs C
- [Type Erasure](/padroes/type-erasure/) — Apagar tipo para interface comum
- [Troubleshooting: Link C](/troubleshooting/zig-c-library-link/) — Problemas de linkagem
