Ошибка 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 так делает
Заголовок раздела «Почему Rust так делает»В Rust всё приватно по умолчанию, и методы — не исключение (смотри Модули). Приватность принадлежит модулю, в котором написан блок impl: любой код в mod bank может вызвать add_interest, а код снаружи — нет.
Так тип может держать маленькие вспомогательные методы, которые имеют смысл только в правильном порядке. Допустим, add_interest должен выполняться раз в месяц, после списания комиссии. Если бы его мог вызвать кто угодно, кто-нибудь случайно вызвал бы его дважды. Приватные помощники плюс один публичный метод, который правильно их запускает, делают такую ошибку невозможной.
Это ещё и оставляет тебе свободу. Приватные методы можно в любой момент переименовать, объединить или удалить, потому что компилятор гарантирует: внешний код ими не пользуется.
Как исправить
Заголовок раздела «Как исправить»Исправление 1: добавь методу pub
Заголовок раздела «Исправление 1: добавь методу pub»Выбирай этот вариант, когда метод задуман для вызова снаружи. Для 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
Что почитать
Заголовок раздела «Что почитать»- E0624 — Rust error codes index (на английском): официальное объяснение с минимальным примером.
- Синтаксис метода — книга «Язык программирования Rust» (перевод на русский): методы, ассоциированные функции и блоки
impl. - Пути для ссылки на элемент в дереве модулей — книга «Язык программирования Rust» (перевод на русский): как шаг за шагом открывать элементы через
pub. - Тестирование приватных функций — книга «Язык программирования Rust» (перевод на русский): почему модульные тесты могут вызывать приватный код.
- Visibility and privacy — The Rust Reference (на английском): точные правила, включая
pub(crate),pub(super)иpub(in path).