Rustlings Arena
← Voltar para a Arena

Erros Comuns do Compilador Rust

Os erros Rust mais frequentes explicados com exemplos e soluções.

E0382

Uso de Valor Movido

error[E0382]: use of moved value: `s1`

Quando você atribui um valor alocado no heap (como String ou Vec) a outra variável, o ownership é movido para a nova variável. O original deixa de existir — você não pode usá-lo depois. Este é o sistema de ownership do Rust eliminando bugs de use-after-free em tempo de compilação.

❌ Broken
let s1 = String::from("hello");
let s2 = s1;          // s1 moves into s2
println!("{}", s1);   // ❌ E0382: s1 was moved
✅ Fixed
let s1 = String::from("hello");
let s2 = s1.clone();  // deep copy — both stay valid
println!("{} {}", s1, s2); // ✅

// Or borrow instead of moving:
let s2 = &s1;
println!("{} {}", s1, s2); // ✅
💡 Tip: Tipos primitivos (i32, bool, char, f64) implementam Copy e são duplicados automaticamente. Tipos de heap (String, Vec, Box) são movidos.
E0502

Não é Possível Emprestar como Mutável — Também Emprestado como Imutável

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable

Rust permite muitas referências compartilhadas (&) OU uma exclusiva (&mut) — nunca ambas ao mesmo tempo. Se você tem um empréstimo imutável ativo, não pode fazer um empréstimo mutável até que o imutável termine. Essa regra elimina data races por construção.

❌ Broken
let mut v = vec![1, 2, 3];
let first = &v[0];    // immutable borrow
v.push(4);            // ❌ E0502: mutable borrow while immutable exists
println!("{}", first);
✅ Fixed
let mut v = vec![1, 2, 3];
let first = v[0];     // copy the value out (i32 is Copy)
v.push(4);            // ✅ no active borrow
println!("{}", first);

// Or restructure scope:
let mut v = vec![1, 2, 3];
{
    let first = &v[0];
    println!("{}", first);
}   // first's borrow ends here
v.push(4);            // ✅
💡 Tip: O borrow checker é conservador. Se ele estiver te atrapalhando, tente mover o println para antes, copiar o valor em vez de emprestar, ou usar .clone().
E0499

Não é Possível Emprestar como Mutável Mais de Uma Vez

error[E0499]: cannot borrow `v` as mutable more than once at a time

Apenas uma referência mutável (&mut) pode existir por vez. Isso previne data races em código single-threaded e é a regra fundamental que faz as garantias de concorrência do Rust funcionarem.

❌ Broken
let mut v = vec![1, 2, 3];
let a = &mut v;
let b = &mut v;   // ❌ E0499: second mutable borrow
a.push(4);
b.push(5);
✅ Fixed
let mut v = vec![1, 2, 3];
{
    let a = &mut v;
    a.push(4);
}   // a's borrow ends here
let b = &mut v;   // ✅ now safe
b.push(5);
💡 Tip: Use escopos {} para limitar por quanto tempo um empréstimo mutável vive. Na prática, esse erro frequentemente significa reestruturar sua lógica para que as mutações aconteçam sequencialmente.
E0308

Tipos Incompatíveis

error[E0308]: mismatched types expected `i32`, found `&i32`

O tipo que o compilador inferiu ou espera não corresponde ao que você forneceu. Muito comum ao iterar (iteradores produzem referências), quando uma função retorna () em vez de um valor, ou ao misturar inteiros com e sem sinal.

❌ Broken
// Trailing semicolon returns () instead of i32:
fn double(n: i32) -> i32 {
    n * 2;   // ❌ E0308: returns () not i32
}

// Iterator reference confusion:
let nums = vec![1, 2, 3];
let sum: i32 = nums.iter().sum(); // needs type annotation
✅ Fixed
fn double(n: i32) -> i32 {
    n * 2    // ✅ no semicolon — expression returned
}

// Dereference in closures when iterating:
let nums = vec![1, 2, 3];
let doubled: Vec<i32> = nums.iter().map(|&x| x * 2).collect();
//                                       ^ dereference the &i32
💡 Tip: Um ponto e vírgula no final da última linha de uma função silenciosamente muda o tipo de retorno para (). Este é o erro nº 1 dos iniciantes em Rust.
E0277

Trait Bound Não Satisfeito

error[E0277]: `MyType` doesn't implement `std::fmt::Display`

O tipo não implementa uma trait obrigatória. Mais frequentemente acionado ao tentar usar a formatação {} sem Display, ao tentar comparar tipos sem PartialOrd, ou ao chamar métodos que exigem uma trait específica.

❌ Broken
struct Point { x: i32, y: i32 }

let p = Point { x: 1, y: 2 };
println!("{}", p);  // ❌ E0277: Point doesn't implement Display
println!("{:?}", p); // also fails — needs Debug
✅ Fixed
#[derive(Debug)]
struct Point { x: i32, y: i32 }

let p = Point { x: 1, y: 2 };
println!("{:?}", p);  // ✅ Debug via #[derive(Debug)]

// Implement Display manually for custom formatting:
use std::fmt;
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}
println!("{}", p);  // ✅
💡 Tip: Adicione #[derive(Debug)] para impressão com {:?}. Para impressão com {}, implemente std::fmt::Display manualmente. A maioria dos bounds ausentes são Debug, Display, Clone, PartialEq ou PartialOrd.
E0106

Especificador de Lifetime Ausente

error[E0106]: missing lifetime specifier expected named lifetime parameter

Quando uma função retorna uma referência e tem múltiplos parâmetros de referência, o Rust não consegue inferir de qual entrada vem a referência de saída. Você precisa informá-lo com anotações de lifetime.

❌ Broken
// Compiler doesn't know if the return borrows from x or y:
fn longest(x: &str, y: &str) -> &str {   // ❌ E0106
    if x.len() > y.len() { x } else { y }
}
✅ Fixed
// 'a says: output lives no longer than the shorter input
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {  // ✅
    if x.len() > y.len() { x } else { y }
}

// Single input → no annotation needed (elision rule):
fn first_word(s: &str) -> &str {  // ✅ lifetime elided
    let bytes = s.as_bytes();
    for (i, &b) in bytes.iter().enumerate() {
        if b == b' ' { return &s[..i]; }
    }
    &s[..]
}
💡 Tip: Anotações de lifetime são restrições, não durações. 'a significa 'a saída não pode sobreviver às entradas'. A maioria dos lifetimes é inferida (omitida). Você só precisa de anotações explícitas quando o compilador não consegue descobrir o relacionamento.
E0596

Não é Possível Emprestar como Mutável — Não Declarado como Mutável

error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable

Você tentou modificar uma variável que não foi declarada com mut. Em Rust, variáveis são imutáveis por padrão — o compilador impõe isso para que mutações acidentais sejam detectadas em tempo de compilação.

❌ Broken
let x = 5;
x = 10;        // ❌ E0596: x is immutable

let v = vec![1, 2, 3];
v.push(4);     // ❌ E0596: v is immutable
✅ Fixed
let mut x = 5;   // ✅ mut makes it mutable
x = 10;

let mut v = vec![1, 2, 3];
v.push(4);     // ✅
💡 Tip: Adicione mut depois de let. Adicione mut apenas quando a variável genuinamente precisar mudar — a imutabilidade por padrão captura bugs e facilita o raciocínio sobre o código.
E0384

Não é Possível Atribuir Duas Vezes a uma Variável Imutável

error[E0384]: cannot assign twice to immutable variable `x`

Similar ao E0596, mas acionado por uma segunda atribuição em vez de uma chamada de método. A variável foi declarada sem mut, mas você tentou reatribuí-la.

❌ Broken
let x = 5;
x = 10;  // ❌ E0384
✅ Fixed
let mut x = 5;
x = 10;  // ✅

// Shadowing is another option if you want to "replace" the variable:
let x = 5;
let x = 10;  // ✅ shadowing — creates a new binding named x
💡 Tip: Shadowing (let x = ...) e mutação (mut x = ...) parecem similares, mas são diferentes: shadowing cria uma nova variável (e pode mudar o tipo), mutação modifica o mesmo binding.
E0507

Não é Possível Mover de Conteúdo Emprestado

error[E0507]: cannot move out of `*s` which is behind a shared reference

Você tentou mover um valor de uma referência. Você não pode tomar ownership por meio de um &T — a referência não é dona dos dados.

❌ Broken
fn print_name(s: &String) {
    let owned = *s;  // ❌ E0507: can't move out of &String
    println!("{}", owned);
}
✅ Fixed
fn print_name(s: &String) {
    let owned = s.clone();  // ✅ clone the data
    println!("{}", owned);
}

// Or just use the reference directly:
fn print_name(s: &String) {
    println!("{}", s);  // ✅ no need to own it
}
💡 Tip: Se você só precisa ler o valor, use a referência diretamente. Se precisar de uma cópia de propriedade, chame .clone(). Se precisar de ownership, mude o parâmetro para aceitar T em vez de &T.
E0004

Padrões Não Exaustivos no Match

error[E0004]: non-exhaustive patterns: `None` not covered

Uma expressão match deve tratar todos os casos possíveis. Se alguma variante estiver sem tratamento, o código não compilará. Isso elimina uma classe inteira de bugs em tempo de execução em que casos não tratados causam travamentos.

❌ Broken
let opt: Option<i32> = Some(42);
match opt {
    Some(n) => println!("{}", n),
    // ❌ E0004: None not covered
}
✅ Fixed
match opt {
    Some(n) => println!("{}", n),
    None    => println!("nothing"),  // ✅ exhaustive
}

// Use _ as a catch-all:
match opt {
    Some(n) => println!("{}", n),
    _       => {},  // ✅ handles everything else
}

// Or use if let for a single case:
if let Some(n) = opt {
    println!("{}", n);  // ✅ no else needed
}
💡 Tip: O compilador informa exatamente quais variantes estão faltando. _ é um coringa. if let é um atalho quando você só se preocupa com um padrão.
E0072

Tipo Recursivo tem Tamanho Infinito

error[E0072]: recursive type `List` has infinite size

Um tipo recursivo em que cada variante contém diretamente a si mesma exigiria memória infinita para ser alocado. O Rust precisa conhecer o tamanho de cada tipo em tempo de compilação. A solução é a indireção via Box, que tem um tamanho de ponteiro conhecido.

❌ Broken
enum List {
    Cons(i32, List),  // ❌ E0072: infinite size
    Nil,
}
✅ Fixed
enum List {
    Cons(i32, Box<List>),  // ✅ Box has fixed pointer size (8 bytes)
    Nil,
}

let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
💡 Tip: Box<T> é o ponteiro de heap mais simples. Ele tem um tamanho fixo (um tamanho de ponteiro) independentemente de T, quebrando o cálculo recursivo de tamanho.
E0716

Valor Temporário Descartado Enquanto Emprestado

error[E0716]: temporary value dropped while borrowed

Você criou um valor temporário, tirou uma referência dele e o temporário foi descartado antes de a referência ser usada. A referência ficaria pendente — apontando para memória liberada.

❌ Broken
let s: &str = &String::from("hello")
    .to_uppercase();  // ❌ E0716: temporary dropped

// Also common with chains:
let name = get_user().name;  // if get_user() returns a temp
✅ Fixed
// Bind the temporary to a variable first:
let upper = String::from("hello").to_uppercase();
let s: &str = &upper;  // ✅ upper lives long enough
println!("{}", s);
💡 Tip: Se você receber esse erro, introduza uma variável para guardar o valor intermediário. O lifetime de um binding let se estende até o final do bloco.
E0515

Não é Possível Retornar Valor Referenciando Variável Local

error[E0515]: cannot return value referencing local variable `local`

Você tentou retornar uma referência a uma variável local. Quando a função retorna, a variável local é descartada, deixando uma referência pendente. O Rust previne isso em tempo de compilação.

❌ Broken
fn get_greeting() -> &str {
    let s = String::from("hello");
    &s   // ❌ E0515: s is dropped when function returns
}
✅ Fixed
// Return an owned value:
fn get_greeting() -> String {
    String::from("hello")  // ✅ caller owns it
}

// Or return a &'static str literal:
fn get_greeting() -> &'static str {
    "hello"  // ✅ lives for the entire program
}
💡 Tip: Se você precisar retornar uma referência, ela deve vir das entradas da função (emprestando de um parâmetro) ou ser 'static. Em caso de dúvida, retorne um tipo de propriedade (String, Vec, etc.).
E0369

Operação Binária Não Pode Ser Aplicada

error[E0369]: binary operation `>` cannot be applied to type `T`

Você usou um operador em um tipo genérico T, mas T não tem um trait bound exigindo que esse operador exista. Código genérico deve ser explícito sobre quais operações um tipo suporta.

❌ Broken
fn largest<T>(list: &[T]) -> &T {
    let mut biggest = &list[0];
    for item in list {
        if item > biggest {  // ❌ E0369: T doesn't implement PartialOrd
            biggest = item;
        }
    }
    biggest
}
✅ Fixed
fn largest<T: PartialOrd>(list: &[T]) -> &T {  // ✅ add bound
    let mut biggest = &list[0];
    for item in list {
        if item > biggest {
            biggest = item;
        }
    }
    biggest
}
💡 Tip: Quando você receber E0369, a mensagem de erro informa qual trait você precisa: PartialOrd para comparações, Add para +, Display para {}, etc. Adicione-o como um bound: <T: NomeDaTrait>.
E0428

Nome Definido Múltiplas Vezes

error[E0428]: the name `connect` is defined multiple times

Você definiu dois itens (funções, structs, tipos, etc.) com o mesmo nome no mesmo escopo. Rust não permite isso — nomes devem ser únicos dentro de um módulo.

❌ Broken
fn connect() -> String { "tcp".into() }
fn connect() -> String { "udp".into() }  // ❌ E0428: duplicate
✅ Fixed
fn connect_tcp() -> String { "tcp".into() }
fn connect_udp() -> String { "udp".into() }  // ✅ unique names

// Or use a parameter:
fn connect(protocol: &str) -> String { protocol.into() }
💡 Tip: Isso também acontece com declarações use importando nomes conflitantes. Use as para renomear: use std::io::Error as IoError;
E0061

Número Errado de Argumentos

error[E0061]: this function takes 2 arguments but 3 arguments were supplied

Você chamou uma função com mais ou menos argumentos do que sua assinatura declara. Rust não suporta parâmetros padrão ou funções variádicas (exceto via macros como println!).

❌ Broken
fn add(a: i32, b: i32) -> i32 { a + b }

add(1, 2, 3);  // ❌ E0061: 3 args, expected 2
add(1);        // ❌ E0061: 1 arg, expected 2
✅ Fixed
add(1, 2);  // ✅

// For optional parameters, use Option:
fn greet(name: &str, title: Option<&str>) {
    match title {
        Some(t) => println!("{} {}", t, name),
        None    => println!("{}", name),
    }
}
greet("Alice", None);
greet("Bob", Some("Dr."));
💡 Tip: Rust não tem parâmetros padrão. Use Option<T> para valores opcionais, ou structs builder para funções com muitos campos opcionais.
E0433

Falha ao Resolver — Não Encontrado no Escopo

error[E0433]: failed to resolve: use of undeclared crate or module `HashMap`

Você usou um tipo ou função que não está no escopo. Para tipos da biblioteca padrão fora do prelúdio (como HashMap, BTreeMap, BufReader), você precisa de uma declaração use explícita.

❌ Broken
let mut map = HashMap::new();  // ❌ E0433: HashMap not in scope
✅ Fixed
use std::collections::HashMap;

let mut map = HashMap::new();  // ✅

// Common imports:
use std::collections::{HashMap, HashSet, BTreeMap};
use std::io::{self, BufRead, Write};
use std::fmt;
💡 Tip: O prelúdio do Rust importa automaticamente tipos comuns (Vec, String, Option, Result, etc.). Todo o resto precisa de um use explícito. O Rust Analyzer / rust-analyzer sugerirá o caminho use correto.

Ponto e Vírgula Esperado / Expressão Esperada

error: expected `;`, found `let` error: expected expression, found keyword `fn`

Erros de sintaxe — o parser encontrou algo inesperado. Geralmente um ponto e vírgula faltando, um delimitador não fechado, um erro de digitação em uma palavra-chave ou uma expressão mal posicionada.

❌ Broken
fn main() {
    let x = 5     // ❌ missing semicolon
    let y = 10;

    fn inner() {} // ❌ nested fn needs to be at statement level
    x + y         // if this is a statement, not a return, add ;
}
✅ Fixed
fn main() {
    let x = 5;     // ✅ semicolon added
    let y = 10;

    fn helper() {}  // ✅ nested fn is valid in Rust
    println!("{}", x + y);
}
💡 Tip: As mensagens de erro do Rust quase sempre apontam para a linha certa. Se um erro de ponto e vírgula parecer errado, verifique a linha acima — um ; ausente na instrução anterior coloca o parser em um estado estranho.

Overflow ao Avaliar Requisito

error[E0275]: overflow evaluating the requirement `Box<T>: Sized`

O compilador ficou preso em um loop infinito tentando provar um trait bound. Causado mais comumente por uma implementação de trait recursiva ou um tipo que tenta implementar uma trait que exige a si mesmo.

❌ Broken
// Generic function calling itself with an incompatible bound:
fn process<T: Clone>(x: T) {
    process(x.clone()); // infinite recursion in type inference
}
✅ Fixed
// Add a base case or restructure logic:
fn process(x: String) {
    if x.is_empty() { return; }
    process(x[1..].to_string());
}
💡 Tip: Esse erro quase sempre aponta para um tipo recursivo ou um loop de trait bound. Simplifique as restrições de trait ou adicione parâmetros de tipo explícitos.

Não é Possível Encontrar o Valor Neste Escopo

error[E0425]: cannot find value `x` in this scope

Você referenciou uma variável que não existe no escopo atual. Causas comuns: erro de digitação no nome da variável, variável declarada em um bloco interno que já terminou, ou uma variável de loop usada fora do loop.

❌ Broken
{
    let x = 5;
}
println!("{}", x);  // ❌ x is out of scope

for i in 0..10 { }
println!("{}", i);  // ❌ i only lives inside the for loop
✅ Fixed
let x = 5;         // declare outside the block
{
    println!("{}", x); // ✅ x is in scope
}
println!("{}", x); // ✅ still in scope

// Save the last loop value explicitly:
let mut last = 0;
for i in 0..10 { last = i; }
println!("{}", last);  // ✅
💡 Tip: O escopo em Rust é baseado em blocos. Variáveis só existem desde onde são declaradas até o final do bloco que as contém. Mova a declaração para cima se precisar de um escopo mais amplo.
🦀

Pronto para começar?

26 desafios interativos gratuitos. Sem instalação. Sem conta necessária para começar.

Começar a aprender Rust →