Pular para o conteúdo

Erro E0624 do Rust: method is private (método privado)

O E0624 quer dizer: o método que você chamou existe, mas foi escrito sem pub, então só o código dentro do módulo dele pode chamá-lo. A struct pode ser pública, e o módulo também. Mesmo assim, os métodos começam privados, um por um. É muito comum logo depois de mover um tipo para um módulo próprio, e a correção costuma ser colocar pub antes do fn. Para os outros erros desta série, veja Erros do compilador Rust.

error[E0624]: associated function `new` is private
--> src/main.rs:18:38
|
7 | fn new() -> Account { // sem `pub`
| ------------------- private associated function defined here
...
18 | let mut account = bank::Account::new(); // ❌ função associada privada
| ^^^ private associated function
error[E0624]: method `add_interest` is private
--> src/main.rs:19:13
|
11 | fn add_interest(&mut self) { // sem `pub`
| -------------------------- private method defined here
...
19 | account.add_interest(); // ❌ método privado
| ^^^^^^^^^^^^ private method

Em português: “a função associada new é privada” e “o método add_interest é privado”. Cada erro mostra onde a função privada foi definida (defined here) e onde você tentou chamá-la.

Este é o programa que gera o erro:

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
fn new() -> Account { // sem `pub`
Account { balance: 0 }
}
fn add_interest(&mut self) { // sem `pub`
self.balance += self.balance / 100;
}
}
}
fn main() {
let mut account = bank::Account::new(); // ❌ função associada privada
account.add_interest(); // ❌ método privado
}

O rustc usa dois nomes aqui. Um método recebe self (account.add_interest()). Uma função associada não tem self e é chamada com :: (Account::new()). A regra e a correção são as mesmas para os dois.

Cada erro tem duas setas. A seta ^^^ é a sua chamada. A seta --- mostra a linha do fn que está sem pub. Ou seja, a mensagem diz exatamente onde colocá-lo.

Estar dentro de impl Account não torna um método público, mesmo quando Account é pub. Pense num restaurante: o cardápio é público, então você pode pedir os pratos (os métodos pub). A cozinha tem as próprias etapas, como “picar a cebola”, que você não pode pedir diretamente. Essas etapas são os métodos privados.

Tudo em Rust é privado por padrão, e os métodos não são exceção (veja Módulos). A privacidade pertence ao módulo onde o bloco impl foi escrito: qualquer código em mod bank pode chamar add_interest, e o código de fora não pode.

Isso deixa um tipo ter pequenos métodos auxiliares que só fazem sentido na ordem certa. Imagine que add_interest deve rodar uma vez por mês, depois de cobrar as tarifas. Se qualquer um pudesse chamá-lo, alguém acabaria chamando duas vezes sem querer. Auxiliares privados, mais um método público que os roda do jeito certo, tornam esse erro impossível.

Também deixa as suas opções em aberto. Métodos privados podem ser renomeados, juntados ou apagados a qualquer momento, porque o compilador garante que nenhum código de fora usa esses métodos.

Escolha esta quando o método foi feito para ser chamado de fora. Para o new isso quase sempre é verdade: um construtor que ninguém pode chamar não serve para muita coisa.

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
pub fn new(opening: u64) -> Account {
Account { balance: opening }
}
pub fn add_interest(&mut self) {
self.balance += self.balance / 100; // 1%
}
pub fn balance(&self) -> u64 {
self.balance
}
}
}
fn main() {
let mut account = bank::Account::new(1000);
account.add_interest();
println!("Saldo: {}", account.balance());
}

Saída:

Saldo: 1010
▶ Experimente você mesmo

Correção 2: Chame o método público feito para você

Seção intitulada “Correção 2: Chame o método público feito para você”

Escolha esta quando o método privado é um auxiliar, principalmente em código que você não escreveu. Muitas vezes existe um método público que o chama por você, na ordem certa e com as verificações certas. Aqui, manter add_interest privado é o design correto:

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
pub fn new(opening: u64) -> Account {
Account { balance: opening }
}
// A porta de entrada pública: uma chamada faz o mês inteiro, na ordem certa.
pub fn close_month(&mut self) {
self.charge_fee();
self.add_interest();
}
pub fn balance(&self) -> u64 {
self.balance
}
// Auxiliares privados: chamá-los sozinhos, ou duas vezes, dá resultado errado.
fn charge_fee(&mut self) {
self.balance = self.balance.saturating_sub(5);
}
fn add_interest(&mut self) {
self.balance += self.balance / 100;
}
}
}
fn main() {
let mut account = bank::Account::new(1000);
account.close_month();
println!("Depois de um mês: {}", account.balance());
// account.add_interest(); // ❌ E0624: method `add_interest` is private
}

Saída:

Depois de um mês: 1004
▶ Experimente você mesmo

Uma boa regra: só deixe um método pub se chamá-lo sozinho, a qualquer momento, não tiver como quebrar a struct. Se ele só faz sentido como uma etapa de algo maior, mantenha-o privado e exponha a coisa maior.

Correção 3: Use pub(crate) para “só o meu código”

Seção intitulada “Correção 3: Use pub(crate) para “só o meu código””

Escolha esta quando outros módulos do seu crate precisam do método, mas quem usa a sua biblioteca não deveria. pub(super) (só o módulo pai) funciona do mesmo jeito; a página do E0603 tem uma tabela com todos os níveis.

mod shop {
pub struct Cart {
prices: Vec<u32>,
}
impl Cart {
pub fn new() -> Cart {
Cart { prices: Vec::new() }
}
pub fn add(&mut self, price: u32) {
self.prices.push(price);
}
// Só para o nosso próprio código (como os recibos), não para quem usa a biblioteca.
pub(crate) fn total(&self) -> u32 {
self.prices.iter().sum()
}
}
}
mod receipt {
pub fn print(cart: &crate::shop::Cart) {
println!("Total: {}", cart.total());
}
}
fn main() {
let mut cart = shop::Cart::new();
cart.add(3);
cart.add(5);
receipt::print(&cart);
}

Saída:

Total: 8
▶ Experimente você mesmo

Um porém: num pacote com src/lib.rs e src/main.rs, eles são dois crates. Um pub(crate) fn total em lib.rs é privado para main.rs:

error[E0624]: method `total` is private
--> src/main.rs:3:25
|
3 | println!("{}", cart.total());
| ^^^^^ private method
|
::: src/lib.rs:10:5
|
10 | pub(crate) fn total(&self) -> u32 {
| --------------------------------- private method defined here

O rustc mostra a chamada em src/main.rs e a definição em src/lib.rs. Nesse caso, use pub simples. Veja Cargo e crates.

Correção 4: Leve o código que precisa dele para dentro do módulo

Seção intitulada “Correção 4: Leve o código que precisa dele para dentro do módulo”

Escolha esta quando o método realmente deve continuar privado, mas algum código precisa dele mesmo assim, como uma auditoria ou um teste. O código do mesmo módulo pode chamá-lo, e um módulo filho também: módulos dentro de bank enxergam tudo o que é privado em bank.

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
pub fn new(opening: u64) -> Account {
Account { balance: opening }
}
fn is_suspicious(&self) -> bool {
self.balance > 10_000
}
}
// Um módulo filho pode usar tudo o que é privado no módulo pai.
pub mod audit {
pub fn check(account: &super::Account) -> &'static str {
if account.is_suspicious() { "precisa de revisão" } else { "ok" }
}
}
}
fn main() {
let small = bank::Account::new(500);
let big = bank::Account::new(50_000);
println!("pequena: {}", bank::audit::check(&small));
println!("grande: {}", bank::audit::check(&big));
}

Saída:

pequena: ok
grande: precisa de revisão
▶ Experimente você mesmo

Os testes de unidade funcionam do mesmo jeito. Um mod tests escrito dentro de bank (ou no fim de src/bank.rs) é um módulo filho, então pode chamar métodos privados. Veja Testes:

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn not_suspicious_when_small() {
let account = Account::new(500);
assert!(!account.is_suspicious()); // privado, mas permitido aqui
}
}

Um bloco impl em outro módulo. A privacidade pertence ao módulo onde o impl foi escrito, não à struct. Se Order mora em mod model, mas você escreve impl Order { fn with_tax(&self) ... } dentro de mod pricing, o main recebe method `with_tax` is private, apontando para mod pricing. Correção: pub fn with_tax, ou pub(crate).

Usar um método como valor de função. accounts.iter().map(bank::Account::audit) é a mesma chamada escrita de outro jeito, então dá o mesmo E0624. A correção é a mesma.

Métodos de trait. Você nunca escreve pub em métodos dentro de impl SomeTrait for Type. Eles são tão públicos quanto o trait, e colocar pub é um erro: error[E0449]: visibility qualifiers are not permitted here (qualificadores de visibilidade não são permitidos aqui). Se um método de trait parece estar faltando, você recebe o E0599, e a correção é trazer o trait com use.

Um método privado de um crate. Você achou o método perfeito no código-fonte de um crate no GitHub, mas ele não é pub. Você não pode chamá-lo, e os autores podem mudá-lo em qualquer versão. Procure um método público que faça o serviço na página do crate no docs.rs; só itens pub aparecem lá.

  • E0603: function `x` is private. A mesma ideia para funções soltas, structs e módulos.
  • E0616: field `x` of struct `Y` is private, ao ler ou alterar um campo.
  • E0451: um campo privado ao montar uma struct com Y { ... }. Costuma se resolver com um pub fn new.
  • E0599: no method named `x` found. O método não existe para esse tipo, ou o trait dele não está no escopo.
  • Todos os erros do compilador: a lista completa de páginas de erro.

Teste o que aprendeu

1. pub struct Timer tem impl Timer { fn start() -> Timer { ... } } dentro de mod clock. O que acontece quando o main chama clock::Timer::start()?

2. Que código pode chamar um método privado definido em mod bank?

3. Um add_interest privado só pode rodar uma vez por mês, depois das tarifas. Qual é a melhor correção para o E0624?

Pontuação: 0 / 3