Erro E0424 do Rust: expected value, found module `self` (sem parâmetro self)
O E0424 quer dizer que você escreveu self dentro de uma função que não tem um parâmetro self. Então não existe nenhum “self” para o Rust apontar. É um deslize muito comum, principalmente para quem vem de Java, C# ou JavaScript, onde o this está sempre lá. A correção costuma ser uma palavra só: acrescentar &self na lista de parâmetros da função. Esta página faz parte do guia de erros do compilador.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0424]: expected value, found module `self` --> src/main.rs:7:32 |6 | fn describe() { | -------- this function doesn't have a `self` parameter7 | println!("Player: {}", self.name); // ❌ qual jogador? | ^^^^ `self` value is a keyword only available in methods with a `self` parameter |help: add a `self` receiver parameter to make the associated `fn` a method |6 | fn describe(&self) { | +++++
error[E0599]: no method named `describe` found for struct `Player` in the current scope --> src/main.rs:13:10 |13 | hero.describe(); | ^^^^^^^^ this is an associated function, not a methodEm português: “esperava um valor, encontrei o módulo self”. O compilador avisa que describe não tem parâmetro self, explica que self só existe em métodos com esse parâmetro e sugere acrescentar &self.
Este é o programa que gera o erro:
struct Player { name: String,}
impl Player { fn describe() { println!("Player: {}", self.name); // ❌ qual jogador? }}
fn main() { let hero = Player { name: String::from("Ferris") }; hero.describe();}O segundo erro, o E0599 (“nenhum método chamado describe”), é só um efeito colateral do primeiro. Corrija o E0424 e ele some junto.
O que significa
Seção intitulada “O que significa”Veja os dois rótulos que o rustc coloca no seu código:
- Linha 6:
fn describe()tem os parênteses vazios. O rustc avisa: “this function doesn’t have aselfparameter” (esta função não tem um parâmetroself). - Linha 7:
self.namepede o nome “do jogador em que este método foi chamado”. Só quedescribenão recebeu jogador nenhum, entãoselfnão significa nada aqui.
Uma função dentro de um bloco impl sem parâmetro self é uma função associada (associated function). Ela pertence ao tipo (Player::describe()), não a um valor específico. Uma função com parâmetro self é um método, e só métodos podem usar self.
Pense num formulário que diz “escreva o seu nome aqui”. Ele só faz sentido quando alguém está segurando o formulário. describe() é um formulário que ninguém está segurando.
E por que a mensagem fala em “found module self”? Em Rust, self tem um segundo significado: o módulo atual, como em use self::helpers;. Quando não existe um valor self, o rustc recorre a esse outro significado e reclama que um módulo não é um valor. Pode ignorar a palavra “module”; o problema de verdade é o parâmetro que está faltando.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Em Rust, nada fica escondido. Java e C# dão a todo método não estático um this invisível. O Rust faz você escrever self como primeiro parâmetro, e você ainda diz como o método recebe o valor: só olhando, alterando ou tomando posse dele. Essa escolha faz parte das regras de borrowing (empréstimo), então precisa ficar visível.
Assim, todo mundo que lê o seu código, e o compilador também, sabe exatamente o que um método faz com o valor. fn summary(&self) promete não mudar nada. fn add(&mut self, ...) avisa que muda. fn checkout(self) consome o valor. E o compilador confere essas promessas para você. Métodos e blocos impl estão explicados em Structs.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Acrescente &self, &mut self ou self
Seção intitulada “Correção 1: Acrescente &self, &mut self ou self”Escolha esta quando a função deve trabalhar com um valor que já existe. Na maioria das vezes, é a correção certa. Acrescente o parâmetro que o rustc sugere e chame a função com ponto:
struct Player { name: String,}
impl Player { fn describe(&self) { println!("Jogador: {}", self.name); }}
fn main() { let hero = Player { name: String::from("Ferris") }; hero.describe();}Saída:
Jogador: FerrisO rustc sempre sugere &self, mas existem três tipos. Escolha o que combina com o que o método faz:
| Parâmetro | O método… | Nomes típicos |
|---|---|---|
&self |
só lê o valor | summary, len, is_empty, describe |
&mut self |
altera o valor | add, push, reset, level_up |
self |
consome o valor (toma o ownership, a posse) | into_..., finish, build, checkout |
Aqui estão os três no mesmo tipo:
struct Order { items: Vec<String>,}
impl Order { fn summary(&self) -> String { format!("{} item(ns): {}", self.items.len(), self.items.join(", ")) }
fn add(&mut self, item: &str) { self.items.push(item.to_string()); }
fn checkout(self) -> Vec<String> { self.items }}
fn main() { let mut order = Order { items: Vec::new() }; order.add("café"); order.add("pão de queijo"); println!("{}", order.summary()); let packed = order.checkout(); // order é consumido aqui println!("Embalado: {:?}", packed);}Saída:
2 item(ns): café, pão de queijoEmbalado: ["café", "pão de queijo"]Se você escolher &self mas o método alterar um campo, o compilador avisa na hora (E0594, “cannot assign to self.count, which is behind a & reference”, ou E0596 para chamadas como push). Troque para &mut self. Na dúvida, comece com &self; o self puro é o caso mais raro.
Correção 2: Chame como Tipo::metodo(&valor)
Seção intitulada “Correção 2: Chame como Tipo::metodo(&valor)”Depois que a função tem um parâmetro self, dá para chamá-la de dois jeitos. hero.label() e Player::label(&hero) significam exatamente a mesma coisa: o valor que ficaria antes do ponto vira o primeiro argumento. A forma com ponto é a que você vai escrever quase sempre. A forma Tipo:: é útil quando você quer passar o próprio método para algo como map:
struct Player { name: String, level: u32,}
impl Player { fn label(&self) -> String { format!("{} (nível {})", self.name, self.level) }}
fn main() { let hero = Player { name: String::from("Ferris"), level: 3 }; println!("{}", hero.label()); println!("{}", Player::label(&hero)); // a mesma chamada
let team = vec![hero, Player { name: String::from("Corro"), level: 5 }]; let labels: Vec<String> = team.iter().map(Player::label).collect(); println!("{:?}", labels);}Saída:
Ferris (nível 3)Ferris (nível 3)["Ferris (nível 3)", "Corro (nível 5)"]O que não funciona é Player::label() sem nenhum valor: um método sempre precisa do seu self. Deixar ele de fora dá o E0061, “this function takes 1 argument but 0 arguments were supplied” (esta função recebe 1 argumento, mas nenhum foi passado).
Correção 3: Passe o que a função precisa
Seção intitulada “Correção 3: Passe o que a função precisa”Escolha esta quando ainda não existe um valor, ou quando a função nem está dentro de um bloco impl.
O caso clássico é o construtor. new cria o valor, então não há self de onde ler nada. Passe os dados iniciais para new como parâmetros normais e monte a struct com Self { ... }:
struct Counter { count: u32, step: u32,}
impl Counter { fn new(step: u32) -> Self { Self { count: 0, step } }
fn tick(&mut self) { self.count += self.step; }}
fn main() { let mut counter = Counter::new(5); counter.tick(); counter.tick(); println!("Contagem: {}", counter.count);}Saída:
Contagem: 10Repare nas maiúsculas: Self (com S maiúsculo) é o tipo, então Self { ... } cria um valor novo. self (com s minúsculo) é o valor em que o método foi chamado.
A mesma ideia corrige uma função solta, fora de qualquer bloco impl. Ali o rustc usa uma frase um pouco diferente: “this function can’t have a self parameter” (esta função não pode ter um parâmetro self). Passe a struct por referência:
struct Cart { items: Vec<u32>,}
fn total(cart: &Cart) -> u32 { cart.items.iter().sum()}
// chame assim: total(&cart)Ou mova total para dentro de impl Cart e dê a ela um &self, como na Correção 1. Os dois jeitos estão certos; um método fica mais natural quando a função claramente “fala sobre” um carrinho.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Dentro de new. Escrever self.count = 0; em fn new() -> Self dá E0424, e a sugestão do rustc, fn new(&self) -> Self, não faria sentido (você precisaria de um contador para criar um contador). Correção: monte o valor com Self { count: 0 }, como na Correção 3.
Dentro de uma closure numa função associada. A closure não é o problema; a função em volta dela é:
error[E0424]: expected value, found module `self` --> src/main.rs:8:35 |7 | fn sale_prices(prices: &[u32]) -> Vec<u32> { | ----------- this function doesn't have a `self` parameter8 | prices.iter().map(|p| p - self.discount).collect() | ^^^^ `self` value is a keyword only available in methods with a `self` parameterA mensagem é a mesma: sale_prices não tem parâmetro self, então a closure também não pode usar self.discount. Correção: transforme em método, fn sale_prices(&self, prices: &[u32]), ou passe o número como parâmetro, fn sale_prices(prices: &[u32], discount: u32). Veja Closures.
Em main ou numa função auxiliar. self nunca funciona fora de um bloco impl. Correção: passe a struct como parâmetro (total(&cart)) ou chame um método nela (cart.total()).
Vindo dos métodos “static” do C# ou do Java. Uma função associada sem self é a versão do Rust para um método estático. Se você quer a versão de instância, precisa acrescentar o parâmetro self você mesmo. Veja Rust para desenvolvedores C#.
Erros relacionados
Seção intitulada “Erros relacionados”- E0425: o deslize contrário. Você está num método, mas escreveu
countem vez deself.count. - E0599: “no method named … found” (nenhum método com esse nome). Costuma aparecer logo depois do E0424, porque uma função sem
selfnão pode ser chamada com ponto. - E0061: número errado de argumentos, por exemplo chamar
Player::label()sem o valor. - E0596: você acrescentou
&self, mas o método altera um campo, então precisa de&mut self. Atribuir a um campo desse jeito dá o E0594. - Todos os erros do compilador: a lista completa de páginas de erro.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Dentro de impl Player, fn heal() { self.hp += 10; } dá E0424. Qual é a melhor correção?
2. Por que fn new() -> Self não pode usar self.name?
3. fn label(&self) -> String está definida em Player. Qual chamada é igual a hero.label()?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0424 — Rust error codes index (em inglês): a explicação oficial deste erro, com um exemplo curto.
- Method Syntax — The Rust Book (em inglês):
&self,&mut selfeself, além de funções associadas comonew. - Associated functions and methods — Rust by Example (em inglês): exemplos para rodar com os dois tipos lado a lado.
- A palavra-chave
self— documentação da biblioteca padrão (em inglês): os dois significados deself, o receptor do método e o módulo atual. - Associated items — The Rust Reference (em inglês): as regras exatas para métodos, receptores e funções associadas.