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ção | Descriçã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
- Slice type mismatch — Incompatibilidade de tipos de slice
- Sentinel mismatch — Incompatibilidade de sentinel
- Type mismatch assignment — Tipo incompatível