Ir al contenido

Error E0624 de Rust: method is private (método privado)

E0624 significa: el método que llamaste existe, pero se escribió sin pub, así que solo el código de dentro de su módulo puede llamarlo. El struct puede ser público, y el módulo también. Aun así, los métodos empiezan siendo privados, uno por uno. Es muy común justo después de mover un tipo a su propio módulo, y la solución suele ser añadir pub delante de fn. Esta página forma parte de la guía de errores del compilador.

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

“Associated function new is private” quiere decir “la función asociada new es privada”, y “method add_interest is private”, “el método add_interest es privado”. defined here señala dónde está definido cada uno.

Este es el programa que lo produce:

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
fn new() -> Account { // sin `pub`
Account { balance: 0 }
}
fn add_interest(&mut self) { // sin `pub`
self.balance += self.balance / 100;
}
}
}
fn main() {
let mut account = bank::Account::new(); // ❌ función asociada privada
account.add_interest(); // ❌ método privado
}

rustc usa aquí dos nombres. Un método recibe self (account.add_interest()). Una función asociada no tiene self y se llama con :: (Account::new()). La regla y la solución son las mismas para los dos.

Cada error tiene dos flechas. La flecha ^^^ es tu llamada. La flecha --- muestra la línea fn a la que le falta el pub. Así que el mensaje te dice exactamente dónde añadirlo.

Estar dentro de impl Account no hace público un método, aunque Account sea pub. Piensa en un restaurante: la carta es pública, así que puedes pedir platos (los métodos pub). La cocina tiene sus propios pasos, como “picar cebolla”, que no puedes pedir directamente. Esos son los métodos privados.

En Rust todo es privado por defecto, y los métodos no son una excepción (mira Módulos). La privacidad pertenece al módulo donde está escrito el bloque impl: cualquier código de mod bank puede llamar a add_interest, y el código de fuera no.

Esto deja que un tipo tenga pequeños métodos auxiliares que solo tienen sentido en el orden correcto. Imagina que add_interest debe ejecutarse una vez al mes, después de cobrar las comisiones. Si cualquiera pudiera llamarlo, alguien lo llamaría dos veces sin querer. Con métodos auxiliares privados y un método público que los ejecuta bien, ese error se vuelve imposible.

Además, te deja las manos libres. Los métodos privados se pueden renombrar, juntar o borrar cuando quieras, porque el compilador garantiza que ningún código de fuera los usa.

Elige esta cuando el método está pensado para llamarse desde fuera. Con new casi siempre es así: un constructor que nadie puede llamar no sirve de mucho.

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());
}

Salida:

Saldo: 1010
▶ Pruébalo tú mismo

Solución 2: Llama al método público pensado para ti

Sección titulada «Solución 2: Llama al método público pensado para ti»

Elige esta cuando el método privado es un auxiliar, sobre todo en código que no escribiste tú. A menudo hay un método público que lo llama por ti, en el orden correcto y con las comprobaciones correctas. Aquí, dejar add_interest privado es el diseño correcto:

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
pub fn new(opening: u64) -> Account {
Account { balance: opening }
}
// La entrada pública: una llamada hace todo el mes, en el orden correcto.
pub fn close_month(&mut self) {
self.charge_fee();
self.add_interest();
}
pub fn balance(&self) -> u64 {
self.balance
}
// Auxiliares privados: llamarlos solos, o dos veces, da resultados incorrectos.
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!("Después de un mes: {}", account.balance());
// account.add_interest(); // ❌ E0624: method `add_interest` is private
}

Salida:

Después de un mes: 1004
▶ Pruébalo tú mismo

Una buena regla: haz pub un método solo si llamarlo por sí solo, en cualquier momento no puede romper el struct. Si solo tiene sentido como un paso de algo más grande, déjalo privado y expón eso más grande.

Solución 3: Usa pub(crate) para “solo mi código”

Sección titulada «Solución 3: Usa pub(crate) para “solo mi código”»

Elige esta cuando otros módulos de tu crate necesitan el método, pero la gente que usa tu biblioteca no debería verlo. pub(super) (solo el módulo padre) funciona igual; la página de E0603 tiene una tabla con todos los niveles.

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);
}
// Solo para nuestro propio código (como los recibos), no para quien usa la 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);
}

Salida:

Total: 8
▶ Pruébalo tú mismo

Un detalle: en un paquete con src/lib.rs y src/main.rs, hay dos crates. Un pub(crate) fn total en lib.rs es 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

rustc señala la llamada en main.rs y, debajo, el método pub(crate) definido en lib.rs. Ahí, usa pub a secas. Mira Cargo y crates.

Solución 4: Mueve dentro del módulo el código que lo necesita

Sección titulada «Solución 4: Mueve dentro del módulo el código que lo necesita»

Elige esta cuando el método de verdad debe seguir siendo privado, pero algún código lo necesita igualmente, como una auditoría o una prueba. El código del mismo módulo puede llamarlo, y también un módulo hijo: los módulos de dentro de bank pueden ver todo lo privado de 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
}
}
// Un módulo hijo puede usar todo lo privado de su padre.
pub mod audit {
pub fn check(account: &super::Account) -> &'static str {
if account.is_suspicious() { "revisar, por favor" } else { "ok" }
}
}
}
fn main() {
let small = bank::Account::new(500);
let big = bank::Account::new(50_000);
println!("pequeña: {}", bank::audit::check(&small));
println!("grande: {}", bank::audit::check(&big));
}

Salida:

pequeña: ok
grande: revisar, por favor
▶ Pruébalo tú mismo

Las pruebas unitarias funcionan igual. Un mod tests escrito dentro de bank (o al final de src/bank.rs) es un módulo hijo, así que puede llamar a métodos privados. Mira Pruebas:

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

Un bloque impl en otro módulo. La privacidad pertenece al módulo donde está escrito el impl, no al struct. Si Order vive en mod model pero escribes impl Order { fn with_tax(&self) ... } dentro de mod pricing, entonces main recibe method `with_tax` is private, señalando a mod pricing. Solución: pub fn with_tax, o pub(crate).

Usar un método como valor de función. accounts.iter().map(bank::Account::audit) es la misma llamada escrita de otra forma, así que da el mismo E0624. La solución es la misma.

Métodos de traits. Nunca escribes pub en los métodos de dentro de impl SomeTrait for Type. Son tan públicos como el trait, y añadir pub es un error: error[E0449]: visibility qualifiers are not permitted here (aquí no se permiten modificadores de visibilidad). Si parece que falta un método de un trait, te saldrá E0599, y la solución es importar el trait con use.

Un método privado de un crate. Encontraste el método perfecto en el código fuente de un crate en GitHub, pero no es pub. No puedes llamarlo, y sus autores pueden cambiarlo en cualquier versión. Busca un método público que haga lo mismo en la página del crate en docs.rs; allí solo aparecen los elementos pub.

  • E0603: function `x` is private. La misma idea, pero para funciones sueltas, structs y módulos.
  • E0616: field `x` of struct `Y` is private, al leer o escribir un campo.
  • E0451: un campo privado al construir un struct con Y { ... }. Normalmente se arregla con un pub fn new.
  • E0599: no method named `x` found. El método no existe para ese tipo, o su trait no está en el ámbito (scope).
  • Todos los errores del compilador: la lista completa de páginas de errores.

Comprueba lo aprendido

1. pub struct Timer tiene impl Timer { fn start() -> Timer { ... } } dentro de mod clock. ¿Qué pasa cuando main llama a clock::Timer::start()?

2. ¿Qué código puede llamar a un método privado definido en mod bank?

3. Un add_interest privado solo debe ejecutarse una vez al mes, después de las comisiones. ¿Cuál es la mejor solución para E0624?

Puntuación: 0 / 3