Type Coercion Failed — Como Resolver em Zig

Type Coercion Failed — Como Resolver em Zig

O Que Este Erro Significa

O erro type coercion failed ocorre em tempo de compilação quando Zig tenta converter automaticamente um valor de um tipo para outro e essa conversão não é permitida ou segura. Zig tem regras rígidas de coerção de tipos para prevenir bugs sutis — diferente de C, que faz conversões implícitas perigosas livremente.

Mensagens típicas do compilador:

error: expected type 'u32', found 'i32'
error: type 'u8' cannot represent all values of type 'u16'

Zig permite apenas coerções que são comprovadamente seguras. Para conversões que podem perder dados, o programador deve usar casts explícitos.

Causas Comuns

1. Atribuir Tipo Signed a Unsigned (ou Vice-Versa)

pub fn main() void {
    const a: i32 = 42;
    const b: u32 = a; // ERRO: i32 pode ter valores negativos que u32 não representa
    _ = b;
}

2. Atribuir Tipo Maior a Tipo Menor

pub fn main() void {
    const a: u32 = 100;
    const b: u8 = a; // ERRO: u32 pode ter valores > 255
    _ = b;
}

3. Misturar Inteiro e Float

pub fn main() void {
    const a: f64 = 3.14;
    const b: u32 = a; // ERRO: f64 não coerce para u32
    _ = b;
}

4. Coerção de Ponteiro Incompatível

pub fn main() void {
    var x: u32 = 42;
    const ptr: *u32 = &x;
    const ptr2: *i32 = ptr; // ERRO: *u32 não coerce para *i32
    _ = ptr2;
}

5. Retorno de Tipo Incorreto

fn calcular() u32 {
    const resultado: i64 = 100;
    return resultado; // ERRO: i64 não coerce para u32
}

Como Corrigir

Solucao 1: Usar @intCast para Inteiros

pub fn main() void {
    const a: u32 = 100;
    const b: u8 = @intCast(a); // Conversão explícita — panic se a > 255
    _ = b;
}

Solucao 2: Usar @intFromFloat e @floatFromInt

pub fn main() void {
    const f: f64 = 3.14;
    const i: u32 = @intFromFloat(f); // Converte float para int (trunca)
    _ = i; // i == 3

    const j: u32 = 42;
    const g: f64 = @floatFromInt(j); // Converte int para float
    _ = g; // g == 42.0
}

Solucao 3: Usar @as para Coerção Explícita

pub fn main() void {
    // @as faz coerção quando ela é segura
    const a: u8 = 42;
    const b: u32 = @as(u32, a); // u8 -> u32 é sempre seguro (widening)
    _ = b;
}

Solucao 4: Usar @bitCast para Reinterpretação

pub fn main() void {
    const a: i32 = -1;
    const b: u32 = @bitCast(a); // Mesmo padrão de bits, tipo diferente
    _ = b; // b == 4294967295
}

Solucao 5: Usar std.math.cast para Conversão Segura

const std = @import("std");

pub fn main() void {
    const a: i32 = -5;
    const b: ?u32 = std.math.cast(u32, a);
    if (b) |valor| {
        std.debug.print("Conversão ok: {}\n", .{valor});
    } else {
        std.debug.print("Valor negativo, não pode converter\n", .{});
    }
}

Solucao 6: Ajustar o Tipo da Variável

Muitas vezes a melhor solução é usar o tipo correto desde o início:

pub fn main() void {
    // Ao invés de converter, use o tipo certo
    const largura: u32 = 800;
    const metade: u32 = largura / 2; // Sem conversão necessária
    _ = metade;
}

Coerções Permitidas Automaticamente

Zig permite certas coerções implícitas que são sempre seguras:

pub fn main() void {
    // Widening (tipo menor para maior) — sempre seguro
    const a: u8 = 42;
    const b: u16 = a;  // OK: u8 -> u16
    const c: u32 = b;  // OK: u16 -> u32
    const d: u64 = c;  // OK: u32 -> u64

    // Ponteiro para slice — seguro
    var arr = [_]u8{ 1, 2, 3 };
    const slice: []u8 = &arr;  // OK

    // *[N]T para []T
    const slice2: []const u8 = &arr;  // OK
    _ = d;
    _ = slice;
    _ = slice2;
}

Coerções Proibidas (Requerem Cast Explícito)

DeParaSolução
i32u32@intCast ou @bitCast
u32u8@intCast (panic se > 255)
f64u32@intFromFloat
u32f64@floatFromInt
*u32*i32@ptrCast
usizeu32@intCast

Comptime vs Runtime

Em comptime, Zig pode avaliar se a conversão é segura:

pub fn main() void {
    // Em comptime, o compilador verifica o valor real
    const a: comptime_int = 42;
    const b: u8 = a; // OK: 42 cabe em u8
    _ = b;

    const c: comptime_int = 300;
    // const d: u8 = c; // ERRO: 300 não cabe em u8
    _ = c;
}

Erros Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.