expected return expression — Como Resolver em Zig
O Que Este Erro Significa
O erro expected return expression ocorre quando uma função em Zig declara um tipo de retorno diferente de void, mas o compilador detecta que existe um caminho de execução que termina sem uma expressão return adequada. Zig exige que todas as funções com tipo de retorno não-void retornem explicitamente um valor em todos os caminhos possíveis.
Causas Comuns
1. Função Sem Return
fn calcular(x: i32) i32 {
const resultado = x * 2;
// ERRO: função termina sem return
_ = resultado;
}
2. Return Apenas em Alguns Branches
fn classificar(n: i32) []const u8 {
if (n > 0) {
return "positivo";
} else if (n < 0) {
return "negativo";
}
// ERRO: e se n == 0? Não há return para esse caso
}
3. Switch Sem Cobertura Completa
const Cor = enum { vermelho, verde, azul };
fn nomeCor(c: Cor) []const u8 {
switch (c) {
.vermelho => return "vermelho",
.verde => return "verde",
// ERRO: falta o caso .azul
}
}
4. Loop que Pode Não Executar
fn encontrar(arr: []const u32, alvo: u32) u32 {
for (arr) |item| {
if (item == alvo) return item;
}
// ERRO: e se o array estiver vazio ou o item não for encontrado?
}
5. Confundir void com Tipo de Retorno
fn processar(dados: []const u8) []const u8 {
if (dados.len == 0) {
return; // ERRO: return sem valor em função que retorna []const u8
}
return dados;
}
Como Corrigir
Solução 1: Adicionar Return Explícito
fn calcular(x: i32) i32 {
const resultado = x * 2;
return resultado; // Correto: retorna o valor
}
Solução 2: Cobrir Todos os Branches
fn classificar(n: i32) []const u8 {
if (n > 0) {
return "positivo";
} else if (n < 0) {
return "negativo";
} else {
return "zero"; // Correto: todos os caminhos cobertos
}
}
Solução 3: Usar else em Switch
const Cor = enum { vermelho, verde, azul };
fn nomeCor(c: Cor) []const u8 {
return switch (c) {
.vermelho => "vermelho",
.verde => "verde",
.azul => "azul", // Correto: todos os casos cobertos
};
}
Se você quer garantir exaustividade sem usar else:
fn nomeCor(c: Cor) []const u8 {
return switch (c) {
.vermelho => "vermelho",
.verde => "verde",
.azul => "azul",
// Se um novo valor for adicionado ao enum, este switch
// dará erro de compilação — forçando você a tratá-lo
};
}
Solução 4: Adicionar Return Após Loop
fn encontrar(arr: []const u32, alvo: u32) ?u32 {
for (arr) |item| {
if (item == alvo) return item;
}
return null; // Correto: retorna null se não encontrado
}
Ou usando error:
const BuscaError = error{NaoEncontrado};
fn encontrar(arr: []const u32, alvo: u32) BuscaError!u32 {
for (arr) |item| {
if (item == alvo) return item;
}
return BuscaError.NaoEncontrado;
}
Solução 5: Usar unreachable Quando Apropriado
Se você tem certeza absoluta de que um caminho nunca será alcançado:
fn dividir(a: u32, b: u32) u32 {
if (b != 0) {
return a / b;
}
unreachable; // Você garante que b nunca será 0
}
Cuidado: unreachable causa comportamento indefinido se for alcançado. Use apenas quando realmente puder garantir que o caminho é impossível.
Padrões Recomendados
Expressão Switch Como Retorno
Em vez de return em cada braço, use switch como expressão:
fn obterPrioridade(nivel: u8) []const u8 {
return switch (nivel) {
0 => "baixa",
1 => "média",
2 => "alta",
3 => "crítica",
else => "desconhecida",
};
}
Expressão if Como Retorno
fn absoluto(n: i32) u32 {
return if (n >= 0) @intCast(n) else @intCast(-n);
}
Retorno Antecipado (Early Return)
O padrão de retorno antecipado é idiomático em Zig:
fn processar(dados: ?[]const u8) []const u8 {
const d = dados orelse return "vazio"; // Retorno antecipado
if (d.len == 0) return "vazio";
return d;
}
Diferença Entre void e noreturn
void: A função não retorna nenhum valor, mas retorna o controle ao chamadornoreturn: A função nunca retorna (ex: loop infinito, @panic, exit)
fn saudacao() void {
// OK sem return — tipo de retorno é void
std.debug.print("Olá!\n", .{});
}
fn falhar() noreturn {
@panic("erro fatal"); // Nunca retorna
}
Erros Relacionados
- unreachable code — Código após return que nunca executa
- expected expression — Expressão esperada pelo compilador
- expected type ‘X’, found ‘Y’ — Tipo de retorno incompatível