---
title: "Zig para Programadores Kotlin"
url: "https://ziglang.com.br/artigos/zig-para-programadores-kotlin/"
markdown_url: "https://ziglang.com.br/artigos/zig-para-programadores-kotlin.MD"
description: "Guia de Zig para desenvolvedores Kotlin. Mapeamento de conceitos: null safety, data classes vs structs, coroutines vs threads, extension functions, generics vs comptime."
date: "2026-02-21"
author: "Zig Brasil"
---

# Zig para Programadores Kotlin

Guia de Zig para desenvolvedores Kotlin. Mapeamento de conceitos: null safety, data classes vs structs, coroutines vs threads, extension functions, generics vs comptime.


## Introdução

Kotlin e Zig são linguagens com prioridades diferentes mas que compartilham valores interessantes. Ambas valorizam null safety, expressividade concisa e pragmatismo. Kotlin opera no ecossistema JVM (e Kotlin/Native), enquanto Zig é uma linguagem de sistemas que compila diretamente para código nativo sem runtime.

Este guia ajuda desenvolvedores Kotlin a entender Zig mapeando conceitos familiares. Para perspectivas de outras linguagens, veja [Zig para Programadores Java](/artigos/zig-para-programadores-java/) e [Zig para Programadores C#](/artigos/zig-para-programadores-csharp/).

## Mapeamento de Conceitos

| Kotlin | Zig | Notas |
|--------|-----|-------|
| `val x = 42` | `const x: i32 = 42` | Imutável |
| `var x = 42` | `var x: i32 = 42` | Mutável |
| `String?` (nullable) | `?[]const u8` (optional) | Null safety |
| `data class` | `struct` | Sem métodos gerados |
| `sealed class` | `union(enum)` | Tagged unions |
| `interface` | Comptime duck typing | Sem dispatch dinâmico |
| Generics `<T>` | `comptime T: type` | Compilação |
| `when` | `switch` | Exaustivo em ambas |
| `?.` (safe call) | `if (opt) \|v\|` | Unwrap seguro |
| `?:` (Elvis) | `orelse` | Valor padrão |
| Coroutines | `std.Thread` | Sem green threads |
| GC (JVM) | Allocators | Manual |
| `fun` | `fn` | Funções |
| Extension functions | Não existe | Usar funções livres |

## Null Safety

Kotlin e Zig tratam null safety como prioridade, mas com abordagens diferentes:

### Kotlin

```kotlin
val nome: String? = obterNome()
val tamanho = nome?.length ?: 0
val garantido = nome ?: "padrão"

// Smart cast
if (nome != null) {
    println(nome.length)  // nome é String aqui, não String?
}
```

### Zig

```zig
const nome: ?[]const u8 = obterNome();
const tamanho = if (nome) |n| n.len else 0;
const garantido = nome orelse "padrão";

// Unwrap seguro
if (nome) |n| {
    std.debug.print("Tamanho: {}\n", .{n.len});
}
```

Ambas as linguagens forçam tratamento explícito de valores nulos em tempo de compilação. A diferença é sintática — Kotlin usa `?.` e `?:`, Zig usa `if (opt) |v|` e `orelse`.

## Data Classes vs Structs

### Kotlin

```kotlin
data class Ponto(val x: Double, val y: Double)

val p1 = Ponto(1.0, 2.0)
val p2 = p1.copy(x = 3.0)
println(p1 == p2)  // comparação estrutural automática
println(p1)  // toString automático: Ponto(x=1.0, y=2.0)
```

### Zig

```zig
const Ponto = struct {
    x: f64,
    y: f64,

    pub fn copiar(self: Ponto) Ponto {
        return self; // cópia por valor
    }

    pub fn comX(self: Ponto, novo_x: f64) Ponto {
        var copia = self;
        copia.x = novo_x;
        return copia;
    }

    pub fn igual(self: Ponto, outro: Ponto) bool {
        return self.x == outro.x and self.y == outro.y;
    }
};

const p1 = Ponto{ .x = 1.0, .y = 2.0 };
const p2 = p1.comX(3.0);
const iguais = p1.igual(p2);
```

Zig structs são value types por padrão (como `data class`), mas não geram automaticamente `equals`, `hashCode`, `toString` ou `copy`. Você implementa o que precisa.

## Sealed Classes vs Tagged Unions

### Kotlin

```kotlin
sealed class Resultado {
    data class Sucesso(val valor: String) : Resultado()
    data class Erro(val codigo: Int, val mensagem: String) : Resultado()
    object Carregando : Resultado()
}

fun processar(r: Resultado) = when (r) {
    is Resultado.Sucesso -> println("OK: ${r.valor}")
    is Resultado.Erro -> println("Erro ${r.codigo}: ${r.mensagem}")
    Resultado.Carregando -> println("Carregando...")
}
```

### Zig

```zig
const Resultado = union(enum) {
    sucesso: []const u8,
    erro: struct { codigo: i32, mensagem: []const u8 },
    carregando: void,
};

fn processar(r: Resultado) void {
    switch (r) {
        .sucesso => |valor| std.debug.print("OK: {s}\n", .{valor}),
        .erro => |e| std.debug.print("Erro {}: {s}\n", .{ e.codigo, e.mensagem }),
        .carregando => std.debug.print("Carregando...\n", .{}),
    }
}
```

`union(enum)` em Zig é funcionalmente equivalente a `sealed class` em Kotlin. Ambas garantem exaustividade no `switch`/`when`.

## Error Handling

### Kotlin

```kotlin
// Kotlin pode usar exceções...
try {
    val resultado = operacaoPerigosa()
} catch (e: IOException) {
    println("Erro: ${e.message}")
}

// ...ou Result type
fun dividir(a: Double, b: Double): Result<Double> =
    if (b == 0.0) Result.failure(ArithmeticException("Divisão por zero"))
    else Result.success(a / b)

dividir(10.0, 3.0)
    .onSuccess { println("Resultado: $it") }
    .onFailure { println("Erro: ${it.message}") }
```

### Zig

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

// Usar try para propagar
const resultado = try dividir(10, 3);

// Ou catch para tratar
const resultado2 = dividir(10, 3) catch |err| {
    std.debug.print("Erro: {}\n", .{err});
    return;
};
```

Zig não tem exceções. Todo erro é tratado via error unions. Veja [Error Sets Customizados](/receitas/zig-error-set-customizado/) e [Padrões Try/Catch](/receitas/zig-try-catch-erros/).

## Generics vs Comptime

### Kotlin

```kotlin
class Fila<T> {
    private val items = mutableListOf<T>()
    fun enfileirar(item: T) = items.add(item)
    fun desenfileirar(): T? = items.removeFirstOrNull()
}
```

### Zig

```zig
fn Fila(comptime T: type) type {
    return struct {
        items: std.ArrayList(T),

        const Self = @This();

        pub fn init(allocator: std.mem.Allocator) Self {
            return .{ .items = std.ArrayList(T).init(allocator) };
        }

        pub fn deinit(self: *Self) void {
            self.items.deinit();
        }

        pub fn enfileirar(self: *Self, item: T) !void {
            try self.items.append(item);
        }

        pub fn desenfileirar(self: *Self) ?T {
            if (self.items.items.len == 0) return null;
            return self.items.orderedRemove(0);
        }
    };
}
```

Generics em Kotlin existem em runtime (com type erasure na JVM). Em Zig, `comptime` gera código especializado para cada tipo.

## Coroutines vs Threads

### Kotlin

```kotlin
suspend fun buscarDados(): String {
    delay(1000) // suspende sem bloquear thread
    return "dados"
}

fun main() = runBlocking {
    val resultado = async { buscarDados() }
    println(resultado.await())
}
```

### Zig

```zig
fn buscarDados() ![]const u8 {
    // operação síncrona — Zig não tem coroutines
    std.time.sleep(1_000_000_000); // 1 segundo
    return "dados";
}

pub fn main() !void {
    const thread = try std.Thread.spawn(.{}, struct {
        fn run() void {
            const dados = buscarDados() catch return;
            std.debug.print("{s}\n", .{dados});
        }
    }.run, .{});
    thread.join();
}
```

Zig usa threads do SO, sem green threads ou coroutines. Veja [Concorrência em Zig](/tutoriais/concorrencia-em-zig/).

## Extension Functions

Kotlin tem extension functions. Zig não:

### Kotlin

```kotlin
fun String.repetirComSeparador(n: Int, sep: String): String =
    (1..n).joinToString(sep) { this }

println("Zig".repetirComSeparador(3, "-"))  // Zig-Zig-Zig
```

### Zig

```zig
// Em Zig, usar funções livres
fn repetirComSeparador(
    allocator: std.mem.Allocator,
    texto: []const u8,
    n: usize,
    sep: []const u8,
) ![]u8 {
    var resultado = std.ArrayList(u8).init(allocator);
    for (0..n) |i| {
        if (i > 0) try resultado.appendSlice(sep);
        try resultado.appendSlice(texto);
    }
    return resultado.toOwnedSlice();
}
```

## Gerenciamento de Memória

A diferença fundamental: Kotlin roda na JVM com garbage collector. Zig usa allocators manuais:

```zig
// Padrão de gerenciamento de memória em Zig
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var lista = std.ArrayList([]const u8).init(allocator);
    defer lista.deinit();

    try lista.append("Olá");
    try lista.append("Mundo");
}
```

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

## Conclusão

Programadores Kotlin encontrarão paralelos claros em Zig: null safety via optionals, sealed classes via tagged unions, e `when` via `switch` exaustivo. As maiores diferenças são a ausência de GC, a falta de coroutines, e a necessidade de gerenciamento manual de memória.

A transição exige disciplina com alocações, mas oferece performance de baixo nível e controle total. Para começar, visite [Introdução ao Zig](/tutoriais/introducao-ao-zig/) e [Como Instalar Zig](/tutoriais/como-instalar-zig/). Se você também quer se aprofundar em Kotlin, confira o [Kotlin Dev Brasil](https://kotlin.dev.br) para conteúdo em português sobre a linguagem.
