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)
| De | Para | Solução |
|---|---|---|
i32 | u32 | @intCast ou @bitCast |
u32 | u8 | @intCast (panic se > 255) |
f64 | u32 | @intFromFloat |
u32 | f64 | @floatFromInt |
*u32 | *i32 | @ptrCast |
usize | u32 | @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
- Signed/unsigned mismatch — Mistura de signed/unsigned
- Integer truncation — Truncamento de inteiro
- Type mismatch assignment — Tipo incompatível em atribuição
- Pointer cast alignment — Alinhamento de cast de ponteiro