Slice Type Mismatch — Como Resolver em Zig

Slice Type Mismatch — Como Resolver em Zig

O Que Este Erro Significa

O erro de incompatibilidade de tipo de slice ocorre quando o código tenta usar um slice de um tipo onde outro tipo de slice é esperado. Slices em Zig carregam informações sobre mutabilidade (const ou não), tipo do elemento, sentinel (terminador) e alinhamento. Uma incompatibilidade em qualquer dessas propriedades causa erro de compilação.

Mensagens típicas:

error: expected type '[]const u8', found '[]u8'
error: expected type '[]u8', found '*[5]u8'
error: expected type '[:0]const u8', found '[]const u8'

Causas Comuns

1. Passar Slice Mutável onde const É Esperado

fn imprimir(dados: []u8) void { // Espera []u8 mutável
    _ = dados;
}

pub fn main() void {
    const texto: []const u8 = "olá";
    imprimir(texto); // ERRO: []const u8 não coerce para []u8
}

2. Confundir Array com Slice

fn processar(dados: []const u8) void {
    _ = dados;
}

pub fn main() void {
    const arr = [_]u8{ 1, 2, 3 };
    processar(arr); // ERRO: [3]u8 não é []const u8
    // Precisa de &arr
}

3. Sentinel Mismatch

fn funcaoC(texto: [:0]const u8) void { // Espera string terminada em 0
    _ = texto;
}

pub fn main() void {
    const slice: []const u8 = "olá";
    funcaoC(slice); // ERRO: []const u8 não tem sentinel, esperado [:0]const u8
}

4. Tipo de Elemento Diferente

fn processar(dados: []const u32) void {
    _ = dados;
}

pub fn main() void {
    const bytes = [_]u8{ 1, 2, 3, 4 };
    processar(&bytes); // ERRO: []const u8, esperado []const u32
}

5. Retorno de Tipo Errado

fn obterDados() []const u8 {
    var buffer: [100]u8 = undefined;
    return buffer; // ERRO: [100]u8 não é []const u8
}

Como Corrigir

Solucao 1: Usar Referência de Array para Obter Slice

fn processar(dados: []const u8) void {
    _ = dados;
}

pub fn main() void {
    const arr = [_]u8{ 1, 2, 3 };
    processar(&arr); // &[3]u8 coerce para []const u8
}

Solucao 2: Aceitar const Quando Não Precisa Mutar

// ERRADO: exige mutabilidade desnecessariamente
fn contar(dados: []u8) usize {
    return dados.len;
}

// CORRETO: aceita const já que não modifica
fn contarCorreto(dados: []const u8) usize {
    return dados.len;
}

pub fn main() void {
    const texto = "olá mundo";
    // contar(texto); // ERRO
    _ = contarCorreto(texto); // OK
}

Solucao 3: Converter Sentinel Slice

fn funcaoC(texto: [:0]const u8) void {
    _ = texto;
}

pub fn main() void {
    // String literals em Zig já são [:0]const u8
    const texto: [:0]const u8 = "olá";
    funcaoC(texto); // OK

    // Para converter []const u8 para [:0]const u8, precisa garantir o sentinel
    const slice: []const u8 = texto; // Perde o sentinel
    // funcaoC(slice); // ERRO
    _ = slice;

    // Pode usar o literal diretamente
    funcaoC("olá"); // OK — literais são [:0]const u8
}

Solucao 4: Usar @constCast (Com Cuidado)

fn funcaoLegada(dados: [*]u8) void { // API que exige ponteiro mutável
    _ = dados;
}

pub fn main() void {
    var buffer = [_]u8{ 1, 2, 3 };
    const slice: []const u8 = &buffer;

    // @constCast remove const — use APENAS quando seguro
    funcaoLegada(@constCast(slice.ptr));
}

Solucao 5: Converter entre Tipos de Slice com std.mem

const std = @import("std");

pub fn main() void {
    var buffer align(4) = [_]u8{ 0, 0, 0, 1, 0, 0, 0, 2 };

    // Converter []u8 para []u32 (requer alinhamento correto)
    const u32_slice = std.mem.bytesAsSlice(u32, &buffer);
    std.debug.print("primeiro: {}\n", .{u32_slice[0]});

    // Converter []u32 de volta para []u8
    const byte_slice = std.mem.sliceAsBytes(u32_slice);
    std.debug.print("bytes: {}\n", .{byte_slice.len});
}

Solucao 6: Usar Slicing para Obter Tipo Correto

pub fn main() void {
    var arr = [_]u8{ 1, 2, 3, 4, 5 };

    // *[5]u8 -> []u8 via slicing
    const slice: []u8 = arr[0..];

    // []u8 -> []const u8 (coerção automática — widening de const)
    const const_slice: []const u8 = slice;

    _ = const_slice;
}

Regras de Coerção de Slice

Coerções Permitidas (Automáticas)

pub fn main() void {
    var arr = [_]u8{ 1, 2, 3 };

    // *[N]T -> []T (array pointer para slice)
    const s1: []u8 = &arr;

    // []T -> []const T (adicionar const)
    const s2: []const u8 = s1;

    // *[N:s]T -> [:s]T (sentinel array pointer para sentinel slice)
    const literal: [:0]const u8 = "abc";

    // [:s]T -> []T (sentinel slice para slice — perde sentinel)
    const s3: []const u8 = literal;

    _ = s2;
    _ = s3;
}

Coerções Proibidas

// []const T -> []T           NÃO (remover const)
// []T -> *[N]T               NÃO (slice para array pointer)
// []const u8 -> [:0]const u8 NÃO (adicionar sentinel)
// []u8 -> []u32              NÃO (mudar tipo de elemento)

String Literals

Um ponto de confusão frequente: string literals em Zig são *const [N:0]u8, que coerce para [:0]const u8 e para []const u8:

pub fn main() void {
    const a: *const [3:0]u8 = "abc"; // Tipo exato
    const b: [:0]const u8 = "abc";   // Coerção para sentinel slice
    const c: []const u8 = "abc";     // Coerção para slice (perde sentinel)
    _ = a;
    _ = b;
    _ = c;
}

Erros Relacionados

Continue aprendendo Zig

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