---
title: "Guia de Migração: Rust para Zig"
url: "https://ziglang.com.br/tutoriais/guia-de-migra%C3%A7%C3%A3o-rust-para-zig/"
markdown_url: "https://ziglang.com.br/tutoriais/guia-de-migra%C3%A7%C3%A3o-rust-para-zig.MD"
description: "Guia técnico para migrar código Rust para Zig. Conversão de ownership, borrowing, traits, Result/Option, pattern matching, lifetimes e async para equivalentes Zig."
date: "2026-02-21"
author: "Zig Brasil"
---

# Guia de Migração: Rust para Zig

Guia técnico para migrar código Rust para Zig. Conversão de ownership, borrowing, traits, Result/Option, pattern matching, lifetimes e async para equivalentes Zig.


## Introdução

Migrar de Rust para Zig pode parecer contra-intuitivo — por que trocar as garantias de segurança do borrow checker? A resposta geralmente envolve simplicidade: Zig resolve os mesmos problemas com menos complexidade, sem lifetimes, sem traits, sem borrow checker. A segurança vem de verificações em runtime (em debug) e de boas práticas com allocators.

Para comparação detalhada, veja [Zig vs Rust](/artigos/zig-vs-rust/) e [Zig para Desenvolvedores Rust](/artigos/zig-para-desenvolvedores-rust/).

## Pré-requisitos

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

## Ownership e Borrowing

### Rust

```rust
fn processar(dados: Vec<u8>) -> Vec<u8> {
    // dados é movido para esta função
    dados.into_iter().map(|b| b + 1).collect()
}

fn analisar(dados: &[u8]) -> usize {
    // dados é emprestado (borrowed)
    dados.iter().filter(|&&b| b > 0).count()
}
```

### Zig

```zig
fn processar(allocator: std.mem.Allocator, dados: []const u8) ![]u8 {
    const resultado = try allocator.alloc(u8, dados.len);
    for (dados, 0..) |b, i| {
        resultado[i] = b + 1;
    }
    return resultado;
}

fn analisar(dados: []const u8) usize {
    var count: usize = 0;
    for (dados) |b| {
        if (b > 0) count += 1;
    }
    return count;
}
```

Em Zig, não há ownership tracking automático. A responsabilidade é do programador:
- Quem aloca, documenta quem libera
- Use `defer` e `errdefer` para garantir limpeza
- Allocators tornam alocações visíveis

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

## Result e Option

### Rust

```rust
fn dividir(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("Divisão por zero".to_string())
    } else {
        Ok(a / b)
    }
}

fn buscar(id: u32) -> Option<Usuario> {
    if id == 0 { None } else { Some(Usuario { id }) }
}
```

### Zig

```zig
fn dividir(a: f64, b: f64) !f64 {
    if (b == 0) return error.DivisaoPorZero;
    return a / b;
}

fn buscar(id: u32) ?Usuario {
    if (id == 0) return null;
    return Usuario{ .id = id };
}
```

`Result<T,E>` em Rust mapeia para `!T` (error union) em Zig. `Option<T>` mapeia para `?T` (optional). Veja [Error Sets Customizados](/receitas/zig-error-set-customizado/).

### Encadeamento

```rust
// Rust
let resultado = valor
    .ok_or("não encontrado")?
    .processar()?
    .finalizar();
```

```zig
// Zig
const intermediario = valor orelse return error.NaoEncontrado;
const processado = try intermediario.processar();
const resultado = processado.finalizar();
```

## Traits para Comptime

### Rust

```rust
trait Serializar {
    fn serializar(&self) -> Vec<u8>;
    fn tamanho(&self) -> usize;
}

fn salvar<T: Serializar>(item: &T) -> Result<(), std::io::Error> {
    let dados = item.serializar();
    std::fs::write("saida.bin", &dados)
}
```

### Zig

```zig
fn salvar(item: anytype) !void {
    const dados = item.serializar();
    defer item.allocator.free(dados); // se aplicável
    try std.fs.cwd().writeFile("saida.bin", dados);
}

// Com verificação explícita em compilação
fn salvarVerificado(comptime T: type, item: T) !void {
    comptime {
        if (!@hasDecl(T, "serializar")) {
            @compileError("Tipo deve implementar serializar()");
        }
    }
    const dados = item.serializar();
    try std.fs.cwd().writeFile("saida.bin", dados);
}
```

## Pattern Matching

### Rust

```rust
match resultado {
    Ok(valor) => println!("Sucesso: {}", valor),
    Err(e) => eprintln!("Erro: {}", e),
}

match forma {
    Forma::Circulo { raio } => PI * raio * raio,
    Forma::Retangulo { largura, altura } => largura * altura,
    Forma::Triangulo { base, altura } => base * altura / 2.0,
}
```

### Zig

```zig
if (resultado) |valor| {
    std.debug.print("Sucesso: {}\n", .{valor});
} else |err| {
    std.debug.print("Erro: {}\n", .{err});
}

switch (forma) {
    .circulo => |c| std.math.pi * c.raio * c.raio,
    .retangulo => |r| r.largura * r.altura,
    .triangulo => |t| t.base * t.altura / 2.0,
}
```

## Enums com Dados

### Rust

```rust
enum Mensagem {
    Texto(String),
    Imagem { url: String, largura: u32, altura: u32 },
    Ping,
}
```

### Zig

```zig
const Mensagem = union(enum) {
    texto: []const u8,
    imagem: struct {
        url: []const u8,
        largura: u32,
        altura: u32,
    },
    ping: void,
};
```

## Iteradores

### Rust

```rust
let soma: i32 = numeros
    .iter()
    .filter(|&&n| n > 0)
    .map(|&n| n * 2)
    .sum();
```

### Zig

```zig
var soma: i32 = 0;
for (numeros) |n| {
    if (n > 0) {
        soma += n * 2;
    }
}
```

Zig não tem iteradores lazy como Rust. Use loops `for` explícitos — mais verboso, mas mais claro sobre o que acontece.

## Lifetimes

Zig não tem lifetimes. A gestão de tempo de vida é responsabilidade do programador:

### Rust

```rust
struct Parser<'a> {
    input: &'a str,
    pos: usize,
}

impl<'a> Parser<'a> {
    fn new(input: &'a str) -> Self {
        Parser { input, pos: 0 }
    }
}
```

### Zig

```zig
const Parser = struct {
    input: []const u8,
    pos: usize,

    pub fn init(input: []const u8) Parser {
        return .{ .input = input, .pos = 0 };
    }
};
// O programador garante que input vive mais que Parser
```

## Vec, HashMap, String

| Rust | Zig |
|------|-----|
| `Vec<T>` | `std.ArrayList(T)` |
| `HashMap<K,V>` | `std.HashMap(K,V,...)` |
| `String` | `std.ArrayList(u8)` |
| `&str` | `[]const u8` |
| `Box<T>` | `allocator.create(T)` |
| `Arc<T>` | Manual (sem equivalente direto) |

## Closures

### Rust

```rust
let dobrar = |x: i32| x * 2;
let resultado: Vec<i32> = numeros.iter().map(dobrar).collect();
```

### Zig

```zig
// Zig não tem closures com captura
// Usar funções nomeadas ou structs
fn dobrar(x: i32) i32 {
    return x * 2;
}

// Ou usar ponteiros de função
const operacao: *const fn (i32) i32 = dobrar;
```

## Testes

### Rust

```rust
#[test]
fn test_soma() {
    assert_eq!(soma(2, 3), 5);
}
```

### Zig

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

Veja [Testes Unitários](/receitas/zig-teste-unitario-basico/) e [Testes com Allocator](/receitas/zig-teste-com-allocator/).

## Cargo para build.zig

Veja [Migrar de Makefile para build.zig](/tutoriais/migrar-makefile-para-build-zig/) para conceitos similares. O `build.zig` substitui tanto `Cargo.toml` quanto `build.rs`.

## Conclusão

A migração de Rust para Zig troca verificações de compilação (borrow checker) por simplicidade e controle explícito. O código resultante é mais simples de ler e entender, mas exige mais disciplina do programador para garantir segurança de memória.

Se a complexidade do borrow checker está diminuindo a produtividade da sua equipe e o projeto não exige garantias formais de segurança de memória, Zig pode ser uma alternativa pragmática. Consulte [Quando Usar Zig](/artigos/quando-usar-zig/) para avaliar se é a escolha certa. Para quem deseja manter ou aprofundar seus conhecimentos em Rust, o [Rust Lang Brasil](https://rustlang.com.br) oferece conteúdo completo em português.
