Comparar Strings com == — Como Resolver em Zig

Comparar Strings com == — Como Resolver em Zig

O Que Este Erro Significa

Em Zig, o operador == não compara o conteúdo de slices (strings). Quando usado com slices, == compara os ponteiros internos e o comprimento — ou seja, verifica se dois slices apontam para a mesma região de memória, não se possuem os mesmos caracteres. Este é um dos erros mais comuns para iniciantes em Zig vindos de linguagens como Python, JavaScript ou Go.

O erro pode se manifestar como:

error: operator == not allowed for type '[]const u8'

Ou, pior, o código compila mas produz resultados incorretos (comparação de ponteiros ao invés de conteúdo).

Por Que == Não Funciona para Strings

Em Zig, strings são slices ([]const u8). Um slice é composto por um ponteiro e um comprimento. O operador == compara essas representações internas, não o conteúdo apontado:

const std = @import("std");

pub fn main() void {
    const a: []const u8 = "olá";
    const b: []const u8 = "olá";

    // Isso compara PONTEIROS, não conteúdo
    // Pode ser true ou false dependendo de otimizações do compilador
    if (a.ptr == b.ptr) {
        std.debug.print("Mesmo ponteiro\n", .{});
    }

    // ERRO DE COMPILAÇÃO: == não é permitido para []const u8
    // if (a == b) { }
}

Causas Comuns

1. Comparação Direta de Slices

const std = @import("std");

pub fn main() void {
    const nome = "Zig";
    const input: []const u8 = "Zig";

    // ERRO ou resultado incorreto
    // if (nome == input) {
    //     std.debug.print("Iguais\n", .{});
    // }
    _ = nome;
    _ = input;
}

2. Verificar Valor de String em if/switch

const std = @import("std");

fn processar(comando: []const u8) void {
    // ERRADO: == não compara conteúdo de slices
    // if (comando == "ajuda") { ... }

    // ERRADO: switch não funciona diretamente com slices
    // switch (comando) {
    //     "ajuda" => {},
    //     "sair" => {},
    // }
    _ = comando;
}

3. Comparar String Alocada com Literal

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const alocado = try allocator.dupe(u8, "Zig");
    defer allocator.free(alocado);

    const literal: []const u8 = "Zig";

    // Sempre false: ponteiros diferentes, mesmo que conteúdo seja igual
    if (alocado.ptr == literal.ptr) {
        std.debug.print("Iguais\n", .{}); // Nunca executa
    }
}

4. Comparar Resultado de Função com Literal

const std = @import("std");

fn obterNome() []const u8 {
    return "admin";
}

pub fn main() void {
    const nome = obterNome();
    // Não pode comparar slices com ==
    // if (nome == "admin") { ... }
    _ = nome;
}

Como Corrigir

Solucao 1: Usar std.mem.eql

A forma correta e idiomática de comparar conteúdo de slices:

const std = @import("std");

pub fn main() void {
    const a: []const u8 = "olá";
    const b: []const u8 = "olá";

    if (std.mem.eql(u8, a, b)) {
        std.debug.print("Strings são iguais!\n", .{});
    } else {
        std.debug.print("Strings são diferentes\n", .{});
    }
}

Solucao 2: Cadeia de Comparações (Simulando switch)

const std = @import("std");

fn processar(comando: []const u8) void {
    if (std.mem.eql(u8, comando, "ajuda")) {
        std.debug.print("Mostrando ajuda...\n", .{});
    } else if (std.mem.eql(u8, comando, "sair")) {
        std.debug.print("Saindo...\n", .{});
    } else if (std.mem.eql(u8, comando, "listar")) {
        std.debug.print("Listando...\n", .{});
    } else {
        std.debug.print("Comando desconhecido: {s}\n", .{comando});
    }
}

pub fn main() void {
    processar("ajuda");
    processar("sair");
    processar("foo");
}

Solucao 3: Comparação Case-Insensitive

const std = @import("std");

pub fn main() void {
    const a: []const u8 = "Hello";
    const b: []const u8 = "hello";

    // Comparação ignorando maiúsculas/minúsculas (ASCII)
    if (std.ascii.eqlIgnoreCase(a, b)) {
        std.debug.print("Iguais (case-insensitive)\n", .{});
    }
}

Solucao 4: Verificar Prefixo ou Sufixo

const std = @import("std");

pub fn main() void {
    const caminho: []const u8 = "/home/user/documento.txt";

    if (std.mem.startsWith(u8, caminho, "/home")) {
        std.debug.print("Está no diretório home\n", .{});
    }

    if (std.mem.endsWith(u8, caminho, ".txt")) {
        std.debug.print("É um arquivo de texto\n", .{});
    }
}

Solucao 5: Usar HashMap para Lookup de Strings

const std = @import("std");

pub fn main() void {
    // Para múltiplas comparações, use ComptimeStringMap
    const mapa = std.StaticStringMap(u32).initComptime(.{
        .{ "vermelho", 0xFF0000 },
        .{ "verde", 0x00FF00 },
        .{ "azul", 0x0000FF },
    });

    const cor = "verde";
    if (mapa.get(cor)) |valor| {
        std.debug.print("Cor {s} = 0x{X:0>6}\n", .{ cor, valor });
    } else {
        std.debug.print("Cor desconhecida: {s}\n", .{cor});
    }
}

Solucao 6: Comparar Substrings com Slicing

const std = @import("std");

pub fn main() void {
    const texto: []const u8 = "Olá, Zig Brasil!";

    // Extrair substring e comparar
    if (texto.len >= 3 and std.mem.eql(u8, texto[0..3], "Olá")) {
        std.debug.print("Texto começa com Olá\n", .{});
    }

    // Buscar substring
    if (std.mem.indexOf(u8, texto, "Zig")) |pos| {
        std.debug.print("'Zig' encontrado na posição {}\n", .{pos});
    }
}

Funções Úteis de std.mem para Strings

FunçãoDescrição
std.mem.eql(u8, a, b)Compara igualdade de conteúdo
std.mem.startsWith(u8, s, prefix)Verifica prefixo
std.mem.endsWith(u8, s, suffix)Verifica sufixo
std.mem.indexOf(u8, s, sub)Busca substring
std.mem.containsAtLeast(u8, s, 1, sub)Verifica se contém
std.mem.count(u8, s, sub)Conta ocorrências
std.mem.trim(u8, s, chars)Remove caracteres
std.mem.split(u8, s, delim)Divide por delimitador

Comparação com Outras Linguagens

# Python — == compara conteúdo
"abc" == "abc"  # True
// JavaScript — === compara conteúdo para strings
"abc" === "abc"  // true
// Zig — std.mem.eql compara conteúdo
const std = @import("std");
std.mem.eql(u8, "abc", "abc")  // true

A diferença existe porque em Zig, strings são slices (ponteiro + tamanho), e o operador == para ponteiros compara endereços, não conteúdo.

Erros Relacionados

Continue aprendendo Zig

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