Por que o Rust não permite simplesmente comparar String com "olá"?
\n\nSe você está começando a aprender Rust e já se deparou com a necessidade de comparar uma variável do tipo String com algum literal de string como "hello" ou "world", provavelmente já viu um erro estranho do compilador. Você escreve algo como:
let user_input = String::from("start");\nmatch user_input {\n "start" => println!("Começando!"),\n "stop" => println!("Parando!"),\n _ => println!("Comando desconhecido"),\n}\n\n\nE o compilador mostra algo como: "expected struct `String`, found `&str`". Familiar?
\n\nNo Stack Overflow, a pergunta "How to match a String against string literals?" tem milhares de visualizações — é uma verdadeira dor de cabeça para iniciantes. Neste artigo, vamos explicar por que isso acontece e mostrar três maneiras simples de resolver o problema. Você aprenderá como o sistema de propriedade e empréstimo do Rust funciona na prática e deixará de temer os erros do compilador.
\n\nNatureza do conflito: String vs &str
\n\nPara entender o problema, precisamos relembrar os fundamentos. Rust tem dois tipos principais para trabalhar com texto:
\n\n- \n
String— é uma string proprietária, armazenada no heap. Ela pode ser modificada, crescer e diminuir. Exemplo:let s = String::from("hello");\n &str— é uma fatia de string. É uma referência a parte de uma string (ou a um literal de string, que fica armazenado diretamente no binário do programa). Exemplo:"hello"é exatamente&'static str. \n
Quando você escreve match user_input { "start" => ... }, está tentando comparar String com &str. O compilador diz: "Não sei como compará-los diretamente, os tipos são diferentes!". E isso é bom — o Rust protege você de conversões implícitas que poderiam causar perda de desempenho ou bugs ocultos.
Mas como resolver? Existem três soluções simples e elegantes.
\n\nSolução 1: Empréstimo com as_str()
\n\nA maneira mais direta e compreensível é obter uma fatia de string (&str) a partir de String usando o método as_str(). Este método retorna uma referência ao conteúdo da string, sem copiá-la. Fica assim:
fn main() {\n let command = String::from("start");\n\n match command.as_str() {\n "start" => println!("Iniciando sistema..."),\n "stop" => println!("Parando..."),\n "pause" => println!("Pausando..."),\n _ => println!("Comando desconhecido: {}", command),\n }\n}\n\n\nPor que funciona? as_str() retorna um &str, que agora pode ser comparado com literais. O Rust vê que ambos os operandos são &str, e a correspondência de padrões funciona perfeitamente.
Vantagens: simplicidade, legibilidade, custo zero (empréstimo, não cópia).
\n\nDesvantagens: é preciso lembrar de chamar o método. Mas é um detalhe menor.
\n\nSolução 2: Comparação em condição if
\n\nSe você não precisa de todo o poder do match, pode usar if comuns com o método eq() ou o operador ==. O Rust consegue comparar String e &str através da trait PartialEq, que é implementada para esse par de tipos.
fn main() {\n let user_input = String::from("admin");\n\n if user_input == "admin" {\n println!("Acesso permitido!");\n } else if user_input == "guest" {\n println!("Acesso de convidado");\n } else {\n println!("Login inválido");\n }\n}\n\n\nIsso funciona porque o compilador converte automaticamente String para &str durante a comparação. Mas no match essa conversão não ocorre — lá é necessário uma correspondência exata de tipos.