---
title: "Guia de Migração: Go para Zig"
url: "https://ziglang.com.br/tutoriais/guia-de-migra%C3%A7%C3%A3o-go-para-zig/"
markdown_url: "https://ziglang.com.br/tutoriais/guia-de-migra%C3%A7%C3%A3o-go-para-zig.MD"
description: "Guia técnico para migrar código Go para Zig. Conversão de goroutines, channels, interfaces, slices, error handling, defer e padrões idiomáticos Go para equivalentes Zig."
date: "2026-02-21"
author: "Zig Brasil"
---

# Guia de Migração: Go para Zig

Guia técnico para migrar código Go para Zig. Conversão de goroutines, channels, interfaces, slices, error handling, defer e padrões idiomáticos Go para equivalentes Zig.


## Introdução

Go e Zig compartilham valores de simplicidade, mas operam em níveis diferentes. Go tem garbage collector, goroutines e channels; Zig tem allocators manuais, threads do SO e controle de baixo nível. Este guia cobre a conversão prática de código Go para Zig.

Para uma visão conceitual, veja [Zig para Programadores Go](/artigos/zig-para-programadores-go/) e [Zig vs Go](/artigos/zig-vs-go/).

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja [Como Instalar Zig](/tutoriais/como-instalar-zig/)
- Conhecimento de Go
- Familiaridade com Zig. Consulte [Introdução ao Zig](/tutoriais/introducao-ao-zig/)

## Tipos e Variáveis

### Go

```go
var nome string = "Zig Brasil"
idade := 25
var valores []int = []int{1, 2, 3}
mapa := map[string]int{"a": 1, "b": 2}
```

### Zig

```zig
const nome: []const u8 = "Zig Brasil";
var idade: u32 = 25;
const valores = [_]i32{ 1, 2, 3 };

var mapa = std.StringHashMap(i32).init(allocator);
defer mapa.deinit();
try mapa.put("a", 1);
try mapa.put("b", 2);
```

## Structs e Métodos

### Go

```go
type Servidor struct {
    Host string
    Porta int
    ativo bool
}

func (s *Servidor) Iniciar() error {
    s.ativo = true
    return nil
}

func (s Servidor) Endereco() string {
    return fmt.Sprintf("%s:%d", s.Host, s.Porta)
}
```

### Zig

```zig
const Servidor = struct {
    host: []const u8,
    porta: u16,
    ativo: bool,

    pub fn iniciar(self: *Servidor) !void {
        self.ativo = true;
    }

    pub fn endereco(self: Servidor, buffer: []u8) ![]u8 {
        return try std.fmt.bufPrint(buffer, "{s}:{}", .{ self.host, self.porta });
    }
};
```

## Interfaces

### Go

```go
type Reader interface {
    Read(p []byte) (n int, err error)
}

func processar(r Reader) error {
    buf := make([]byte, 1024)
    n, err := r.Read(buf)
    if err != nil {
        return err
    }
    fmt.Println(string(buf[:n]))
    return nil
}
```

### Zig

```zig
// Opção 1: duck typing via anytype (estático)
fn processar(reader: anytype) !void {
    var buf: [1024]u8 = undefined;
    const n = try reader.read(&buf);
    std.debug.print("{s}\n", .{buf[0..n]});
}

// Opção 2: interface explícita com vtable (dinâmico)
const Reader = struct {
    ptr: *anyopaque,
    readFn: *const fn (*anyopaque, []u8) usize,

    pub fn read(self: Reader, buf: []u8) usize {
        return self.readFn(self.ptr, buf);
    }
};
```

## Error Handling

### Go

```go
func abrir(caminho string) (*os.File, error) {
    f, err := os.Open(caminho)
    if err != nil {
        return nil, fmt.Errorf("erro ao abrir %s: %w", caminho, err)
    }
    return f, nil
}

f, err := abrir("config.json")
if err != nil {
    log.Fatal(err)
}
defer f.Close()
```

### Zig

```zig
fn abrir(caminho: []const u8) !std.fs.File {
    return std.fs.cwd().openFile(caminho, .{}) catch |err| {
        std.log.err("erro ao abrir: {}", .{err});
        return err;
    };
}

const f = try abrir("config.json");
defer f.close();
```

Veja [Padrões Try/Catch](/receitas/zig-try-catch-erros/) e [Error Logging](/receitas/zig-error-logging/).

## Slices

### Go

```go
numeros := []int{1, 2, 3, 4, 5}
sub := numeros[1:3]
numeros = append(numeros, 6)
copia := make([]int, len(numeros))
copy(copia, numeros)
```

### Zig

```zig
const numeros_fixo = [_]i32{ 1, 2, 3, 4, 5 };
const sub = numeros_fixo[1..3];

// Para crescimento dinâmico, usar ArrayList
var numeros = std.ArrayList(i32).init(allocator);
defer numeros.deinit();
try numeros.appendSlice(&numeros_fixo);
try numeros.append(6);

// Cópia
const copia = try allocator.dupe(i32, numeros.items);
defer allocator.free(copia);
```

## Goroutines e Channels

### Go

```go
func main() {
    ch := make(chan string, 10)

    go func() {
        ch <- "resultado"
    }()

    valor := <-ch
    fmt.Println(valor)
}
```

### Zig

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

pub fn main() !void {
    var resultado: []const u8 = undefined;
    var mutex = std.Thread.Mutex{};
    var cond = std.Thread.Condition{};

    const thread = try std.Thread.spawn(.{}, struct {
        fn trabalho(r: *[]const u8, m: *std.Thread.Mutex, c: *std.Thread.Condition) void {
            m.lock();
            defer m.unlock();
            r.* = "resultado";
            c.signal();
        }
    }.trabalho, .{ &resultado, &mutex, &cond });

    {
        mutex.lock();
        defer mutex.unlock();
        cond.wait(&mutex);
    }

    std.debug.print("{s}\n", .{resultado});
    thread.join();
}
```

Zig não tem channels nativos. Use mutex, condições, ou atomics. Veja [Concorrência em Zig](/tutoriais/concorrencia-em-zig/).

## Defer

Go e Zig têm `defer`, mas com semântica diferente:

- **Go**: `defer` executa na saída da **função**, em ordem LIFO
- **Zig**: `defer` executa na saída do **escopo** (bloco), em ordem LIFO

```zig
fn exemplo() void {
    {
        const recurso = obterRecurso();
        defer liberarRecurso(recurso);
        // recurso liberado ao sair deste bloco
    }
    // recurso já foi liberado aqui
}
```

Zig também tem `errdefer` — sem equivalente em Go:

```zig
fn criarConexao(allocator: std.mem.Allocator) !*Conexao {
    const conn = try allocator.create(Conexao);
    errdefer allocator.destroy(conn); // só executa se retornar erro

    try conn.conectar();
    return conn;
}
```

Veja [Padrões Errdefer](/receitas/zig-errdefer-pattern/).

## Gerenciamento de Memória

### Go (GC automático)

```go
func criarLista() []string {
    lista := make([]string, 0)
    lista = append(lista, "item1", "item2")
    return lista // GC cuida da memória
}
```

### Zig (manual via allocators)

```zig
fn criarLista(allocator: std.mem.Allocator) !std.ArrayList([]const u8) {
    var lista = std.ArrayList([]const u8).init(allocator);
    errdefer lista.deinit();
    try lista.append("item1");
    try lista.append("item2");
    return lista;
}

// O chamador gerencia o ciclo de vida:
var lista = try criarLista(allocator);
defer lista.deinit();
```

Veja [Substituir malloc/free por Allocators](/tutoriais/zig-substituir-malloc-free/) e [ArenaAllocator](/receitas/zig-arena-allocator/).

## Go Modules para build.zig

### go.mod

```go
module meu-projeto
go 1.21
require github.com/pkg/errors v0.9.1
```

### build.zig

```zig
pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "meu-projeto",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Dependências via build.zig.zon
    b.installArtifact(exe);
}
```

## Testes

### Go

```go
func TestSoma(t *testing.T) {
    if resultado := soma(2, 3); resultado != 5 {
        t.Errorf("esperava 5, obteve %d", resultado)
    }
}

func BenchmarkSoma(b *testing.B) {
    for i := 0; i < b.N; i++ {
        soma(2, 3)
    }
}
```

### Zig

```zig
test "soma" {
    try std.testing.expectEqual(@as(i32, 5), soma(2, 3));
}

// Benchmarks via testes customizados
test "benchmark soma" {
    const timer = try std.time.Timer.start();
    var i: usize = 0;
    while (i < 1_000_000) : (i += 1) {
        _ = soma(2, 3);
    }
    const elapsed = timer.read();
    std.debug.print("Tempo: {}ns\n", .{elapsed});
}
```

Veja [Testes Unitários](/receitas/zig-teste-unitario-basico/) e [Benchmarking](/receitas/zig-benchmark-performance/).

## Conclusão

A migração de Go para Zig troca a conveniência do garbage collector e goroutines pela performance previsível e controle de baixo nível. As maiores adaptações são o gerenciamento manual de memória e a ausência de channels/goroutines nativos.

Para avaliar se a migração faz sentido, leia [Quando Usar Zig](/artigos/quando-usar-zig/). Para começar com Zig, visite [Introdução ao Zig](/tutoriais/introducao-ao-zig/). Se você deseja continuar aprofundando seus conhecimentos em Go paralelamente, visite o [Golang Brasil](https://golang.com.br).
