Перейти к содержимому

Ошибка Rust E0624: method is private (приватный метод)

E0624 значит: метод, который ты вызвал, существует, но написан без pub, поэтому вызывать его может только код внутри его модуля. Структура может быть публичной, и модуль тоже. Методы всё равно поначалу приватные, каждый по отдельности. Чаще всего это случается сразу после того, как ты вынес тип в отдельный модуль, и обычно исправление — добавить pub перед fn. Эта страница — часть справочника по ошибкам компилятора.

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

Компилятор сообщает: ассоциированная функция new и метод add_interest приватные, и показывает, где каждая из них объявлена. Вот программа, которая выдаёт эти ошибки (комментарии no pub значат «нет pub»):

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
fn new() -> Account { // no `pub`
Account { balance: 0 }
}
fn add_interest(&mut self) { // no `pub`
self.balance += self.balance / 100;
}
}
}
fn main() {
let mut account = bank::Account::new(); // ❌ private associated function
account.add_interest(); // ❌ private method
}

rustc использует здесь два названия. Метод (method) принимает self (account.add_interest()). Ассоциированная функция (associated function) не принимает self и вызывается через :: (Account::new()). Правило и исправление для них одни и те же.

У каждой ошибки две стрелки. Стрелка ^^^ — это твой вызов. Стрелка --- показывает строку с fn, где не хватает pub. То есть сообщение говорит точно, куда его добавить.

То, что метод находится внутри impl Account, не делает его публичным, даже если сам Account — pub. Представь ресторан: меню публичное, и ты можешь заказывать блюда (pub-методы). А у кухни есть свои шаги, вроде «нарезать лук», которые напрямую заказать нельзя. Это и есть приватные методы.

В Rust всё приватно по умолчанию, и методы — не исключение (смотри Модули). Приватность принадлежит модулю, в котором написан блок impl: любой код в mod bank может вызвать add_interest, а код снаружи — нет.

Так тип может держать маленькие вспомогательные методы, которые имеют смысл только в правильном порядке. Допустим, add_interest должен выполняться раз в месяц, после списания комиссии. Если бы его мог вызвать кто угодно, кто-нибудь случайно вызвал бы его дважды. Приватные помощники плюс один публичный метод, который правильно их запускает, делают такую ошибку невозможной.

Это ещё и оставляет тебе свободу. Приватные методы можно в любой момент переименовать, объединить или удалить, потому что компилятор гарантирует: внешний код ими не пользуется.

Выбирай этот вариант, когда метод задуман для вызова снаружи. Для new это почти всегда так: конструктор, который никто не может вызвать, мало полезен.

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!("Баланс: {}", account.balance());
}

Вывод:

Баланс: 1010
▶ Попробуй сам

Исправление 2: вызови публичный метод, который предназначен для тебя

Заголовок раздела «Исправление 2: вызови публичный метод, который предназначен для тебя»

Выбирай этот вариант, когда приватный метод — вспомогательный, особенно в чужом коде. Часто есть публичный метод, который вызывает его за тебя, в правильном порядке и с нужными проверками. Здесь оставить add_interest приватным — правильный дизайн:

mod bank {
pub struct Account {
balance: u64,
}
impl Account {
pub fn new(opening: u64) -> Account {
Account { balance: opening }
}
// Публичный вход: один вызов закрывает весь месяц в правильном порядке.
pub fn close_month(&mut self) {
self.charge_fee();
self.add_interest();
}
pub fn balance(&self) -> u64 {
self.balance
}
// Приватные помощники: вызов по отдельности или дважды даёт неверный результат.
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!("Через месяц: {}", account.balance());
// account.add_interest(); // ❌ E0624: method `add_interest` is private
}

Вывод:

Через месяц: 1004
▶ Попробуй сам

Хорошее правило: делай метод pub, только если его вызов сам по себе, в любой момент не может сломать структуру. Если он имеет смысл только как один шаг чего-то большего, оставь его приватным и открой наружу это большее.

Исправление 3: pub(crate) для «только моего кода»

Заголовок раздела «Исправление 3: pub(crate) для «только моего кода»»

Выбирай этот вариант, когда метод нужен другим модулям твоего крейта, но не людям, которые используют твою библиотеку. pub(super) (только родительский модуль) работает так же; на странице E0603 есть таблица всех уровней видимости.

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);
}
// Только для нашего собственного кода (например, чеков), не для пользователей библиотеки.
pub(crate) fn total(&self) -> u32 {
self.prices.iter().sum()
}
}
}
mod receipt {
pub fn print(cart: &crate::shop::Cart) {
println!("Итого: {}", cart.total());
}
}
fn main() {
let mut cart = shop::Cart::new();
cart.add(3);
cart.add(5);
receipt::print(&cart);
}

Вывод:

Итого: 8
▶ Попробуй сам

Одна загвоздка: в пакете, где есть и src/lib.rs, и src/main.rs, это два крейта. pub(crate) fn total в lib.rs для 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

Там используй обычный pub. Смотри Бинарный и библиотечный крейт вместе.

Исправление 4: перенеси нужный код внутрь модуля

Заголовок раздела «Исправление 4: перенеси нужный код внутрь модуля»

Выбирай этот вариант, когда метод действительно должен остаться приватным, но какому-то коду он всё же нужен, например проверке для аудита или тесту. Его может вызвать код в том же модуле, а также дочерний модуль: модули внутри bank видят всё приватное в 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
}
}
// Дочерний модуль может пользоваться всем приватным в родителе.
pub mod audit {
pub fn check(account: &super::Account) -> &'static str {
if account.is_suspicious() { "нужна проверка" } else { "в порядке" }
}
}
}
fn main() {
let small = bank::Account::new(500);
let big = bank::Account::new(50_000);
println!("маленький: {}", bank::audit::check(&small));
println!("большой: {}", bank::audit::check(&big));
}

Вывод:

маленький: в порядке
большой: нужна проверка
▶ Попробуй сам

С модульными тестами то же самое. mod tests, написанный внутри bank (или в конце src/bank.rs), — дочерний модуль, поэтому он может вызывать приватные методы. Смотри урок Тестирование:

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn not_suspicious_when_small() {
let account = Account::new(500);
assert!(!account.is_suspicious()); // приватный, но здесь можно
}
}

Блок impl в другом модуле. Приватность принадлежит модулю, в котором написан impl, а не структуре. Если Order живёт в mod model, а ты пишешь impl Order { fn with_tax(&self) ... } внутри mod pricing, то main получит method `with_tax` is private с указанием на mod pricing. Исправление: pub fn with_tax или pub(crate).

Метод как значение-функция. accounts.iter().map(bank::Account::audit) — это тот же вызов, просто записанный иначе, поэтому он даёт ту же E0624. Исправление то же.

Методы трейтов. Внутри impl SomeTrait for Type никогда не пишут pub у методов. Они настолько же публичны, насколько публичен трейт, а pub там — ошибка: error[E0449]: visibility qualifiers are not permitted here. Если кажется, что метода трейта нет, ты получишь E0599, и исправление — подключить трейт через use.

Приватный метод крейта. Ты нашёл идеальный метод в исходниках крейта на GitHub, но он не pub. Вызвать его нельзя, а авторы могут поменять его в любом релизе. Поищи публичный метод, который делает то же самое, на странице крейта на docs.rs: там видны только pub-элементы.

  • E0603: function `x` is private. Та же идея для обычных функций, структур и модулей.
  • E0616: field `x` of struct `Y` is private при чтении или записи поля.
  • E0451: приватное поле при создании структуры через Y { ... }. Обычно лечится через pub fn new.
  • E0599: no method named `x` found. У этого типа нет такого метода, или его трейт не в области видимости.
  • Все ошибки компилятора: полный список страниц об ошибках.

Проверь себя

1. У pub struct Timer есть impl Timer { fn start() -> Timer { ... } } внутри mod clock. Что будет, если main вызовет clock::Timer::start()?

2. Какой код может вызвать приватный метод, объявленный в mod bank?

3. Приватный add_interest должен выполняться только раз в месяц, после списания комиссии. Как лучше всего исправить E0624?

Результат: 0 / 3