Type Coercion em Zig — O que é e Como Usar

Type Coercion em Zig — O que é e Como Usar

Definição

Type coercion (coerção de tipos) em Zig é o processo de converter um valor de um tipo para outro. Zig possui um sistema de coerção cuidadosamente projetado que permite conversões implícitas apenas quando são seguras e sem perda de informação. Para conversões que podem perder dados ou alterar a semântica, Zig exige conversão explícita usando builtins como @intCast, @floatFromInt, @ptrCast, etc.

Essa abordagem elimina uma classe inteira de bugs comuns em C, onde conversões implícitas silenciosas podem truncar valores ou mudar sinais.

Por que Type Coercion Importa

  1. Segurança: Conversões que podem perder dados exigem declaração explícita do programador.
  2. Clareza: O código expressa exatamente onde conversões acontecem.
  3. Previsibilidade: Sem surpresas de promoção implícita como em C (integer promotion rules).
  4. Portabilidade: O comportamento é o mesmo em todas as arquiteturas.

Exemplo Prático

Coerções Implícitas (Seguras)

const std = @import("std");

pub fn main() void {
    // comptime_int para qualquer tipo inteiro que comporte o valor
    const a: u32 = 42;
    const b: i64 = 42;

    // Widening: tipo menor para tipo maior (sem perda)
    const c: u16 = 100;
    const d: u32 = c; // u16 -> u32 implícito

    // Ponteiro para slice
    var array = [_]u8{ 1, 2, 3 };
    const slice: []u8 = &array; // *[3]u8 -> []u8 implícito

    // const qualification: T -> const T
    const ptr_mut: *u32 = @constCast(&a);
    _ = ptr_mut;

    std.debug.print("{} {} {}\n", .{ d, b, slice.len });
}

Coerções Explícitas (Potencialmente Inseguras)

const std = @import("std");

pub fn main() void {
    // Narrowing: tipo maior para tipo menor (pode perder dados)
    const grande: u32 = 200;
    const pequeno: u8 = @intCast(grande); // explícito!

    // Float para inteiro (perde parte fracionária)
    const pi: f64 = 3.14;
    const inteiro: i32 = @intFromFloat(pi); // 3

    // Inteiro para float
    const n: i32 = 42;
    const f: f64 = @floatFromInt(n); // 42.0

    std.debug.print("{} {} {d}\n", .{ pequeno, inteiro, f });
}

Coerção com Optionals e Error Unions

const std = @import("std");

fn buscar(id: u32) ?[]const u8 {
    if (id == 1) return "encontrado"; // []const u8 -> ?[]const u8 implícito
    return null;
}

fn calcular(x: u32) !u32 {
    if (x == 0) return error.DivisaoPorZero;
    return 100 / x; // u32 -> !u32 implícito
}

pub fn main() void {
    const resultado = buscar(1);
    if (resultado) |valor| {
        std.debug.print("{s}\n", .{valor});
    }

    const calc = calcular(5) catch 0;
    std.debug.print("{}\n", .{calc}); // 20
}

Regras de Coerção Implícita

DeParaPermitido
comptime_intQualquer inteiro que comporteSim
comptime_floatf32, f64Sim
u8u16, u32, u64Sim (widening)
u32u16, u8Apenas explícito (@intCast)
*[N]T[]TSim
T?TSim
TE!TSim
*T*const TSim

Armadilhas Comuns

  • Comparar tipos diferentes: == entre u32 e i32 não é permitido. Converta explicitamente primeiro.
  • Aritmética mista: Somar u8 com u32 exige que ambos estejam no mesmo tipo. Use @as ou @intCast.
  • Literais negativos em unsigned: const x: u32 = -1; é erro de compilação. Zig não permite conversão implícita de valor negativo para unsigned.
  • Perda de precisão float: Converter f64 para f32 exige @floatCast, pois pode perder precisão.

Termos Relacionados

  • comptime_int — Tipo que pode ser coagido para qualquer inteiro
  • comptime_float — Tipo que pode ser coagido para qualquer float
  • anytype — Inferência de tipo para parâmetros genéricos
  • Pointer Types — Coerção entre tipos de ponteiro

Tutoriais Relacionados

Continue aprendendo Zig

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