Ошибка Rust E0424: expected value, found module `self` (self вне метода)
E0424 значит, что ты написал self внутри функции, у которой нет параметра self, так что Rust не на что указать словом «self». Это очень частая оплошность, особенно если ты пришёл из Java, C# или JavaScript, где this есть всегда. Обычно исправление — одно слово: добавь &self в список параметров функции. Эта страница — часть руководства по ошибкам компилятора.
Сообщение об ошибке
Заголовок раздела «Сообщение об ошибке»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); // ❌ which player? | ^^^^ `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 methodКомпилятор говорит: ожидалось значение, а найден модуль self; значение self доступно только в методах с параметром self. Подсказка предлагает добавить &self. Вот программа, которая выдаёт эту ошибку:
struct Player { name: String,}
impl Player { fn describe() { println!("Player: {}", self.name); // ❌ which player? }}
fn main() { let hero = Player { name: String::from("Ferris") }; hero.describe();}Комментарий спрашивает: «какой игрок?». Вторая ошибка, E0599, — побочный эффект первой. Исправь E0424, и она тоже исчезнет.
Что это значит
Заголовок раздела «Что это значит»Посмотри на две подписи, которые rustc ставит к твоему коду:
- Строка 6: у
fn describe()пустые скобки. rustc отмечает: «this function doesn’t have aselfparameter» (у этой функции нет параметраself). - Строка 7:
self.nameпросит имя «того игрока, у которого вызвали метод». Ноdescribeникакого игрока не получала, поэтомуselfздесь ничего не значит.
Функция внутри блока impl без параметра self называется ассоциированной функцией (associated function). Она принадлежит типу (Player::describe()), а не какому-то одному значению. Функция с параметром self — это метод, и только методы могут говорить self.
Представь бланк с надписью «впиши сюда своё имя». Он имеет смысл, только когда кто-то держит его в руках. describe() — бланк, который никто не держит.
Почему там написано «found module self»? В Rust у self есть второе значение: текущий модуль, как в use self::helpers;. Когда значения self нет, rustc берёт это значение и жалуется, что модуль — не значение. На слово «module» можно не обращать внимания: настоящая проблема — отсутствующий параметр.
Почему Rust так делает
Заголовок раздела «Почему Rust так делает»В Rust ничего не спрятано. Java и C# дают каждому нестатическому методу невидимый this. Rust заставляет написать self первым параметром, и ты заодно говоришь, как метод его получает: только смотрит, изменяет или забирает владение. Этот выбор — часть правил заимствования, поэтому он должен быть виден.
Так каждый, кто читает твой код, и компилятор точно знают, что метод делает со своим значением. fn summary(&self) обещает ничего не менять. fn add(&mut self, ...) предупреждает, что меняет. fn checkout(self) расходует значение. А компилятор проверяет эти обещания за тебя. Методы и блоки impl разобраны в уроке Структуры.
Как исправить
Заголовок раздела «Как исправить»Исправление 1: добавь &self, &mut self или self
Заголовок раздела «Исправление 1: добавь &self, &mut self или self»Выбирай это, когда функция должна работать с одним уже существующим значением. Чаще всего это правильное исправление. Добавь параметр, который предлагает rustc, и вызывай через точку:
struct Player { name: String,}
impl Player { fn describe(&self) { println!("Игрок: {}", self.name); }}
fn main() { let hero = Player { name: String::from("Ferris") }; hero.describe();}Вывод:
Игрок: Ferrisrustc всегда предлагает &self, но вариантов три. Выбери тот, что подходит к делу метода:
| Параметр | Метод… | Типичные имена |
|---|---|---|
&self |
только читает значение | summary, len, is_empty, describe |
&mut self |
изменяет значение | add, push, reset, level_up |
self |
расходует значение (забирает владение) | into_..., finish, build, checkout |
Вот все три на одном типе:
struct Order { items: Vec<String>,}
impl Order { fn summary(&self) -> String { format!("Позиций: {} — {}", 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("кофе"); order.add("бублик"); println!("{}", order.summary()); let packed = order.checkout(); // здесь order расходуется println!("Упаковано: {:?}", packed);}Вывод:
Позиций: 2 — кофе, бубликУпаковано: ["кофе", "бублик"]Если ты выбрал &self, а метод меняет поле, компилятор сразу скажет об этом (E0594 «cannot assign to self.count, which is behind a & reference» или E0596 для вызовов вроде push). Тогда переходи на &mut self. Если сомневаешься, начинай с &self; self нужен редко.
Исправление 2: вызывай как Type::method(&value)
Заголовок раздела «Исправление 2: вызывай как Type::method(&value)»Когда у функции есть параметр self, её можно вызвать двумя способами. hero.label() и Player::label(&hero) значат одно и то же: значение, которое стоит перед точкой, становится первым аргументом. Чаще всего ты будешь писать через точку. Форма через Type:: удобна, когда хочешь передать сам метод куда-нибудь, например в map:
struct Player { name: String, level: u32,}
impl Player { fn label(&self) -> String { format!("{} (уровень {})", self.name, self.level) }}
fn main() { let hero = Player { name: String::from("Ferris"), level: 3 }; println!("{}", hero.label()); println!("{}", Player::label(&hero)); // тот же вызов
let team = vec![hero, Player { name: String::from("Corro"), level: 5 }]; let labels: Vec<String> = team.iter().map(Player::label).collect(); println!("{:?}", labels);}Вывод:
Ferris (уровень 3)Ferris (уровень 3)["Ferris (уровень 3)", "Corro (уровень 5)"]А вот Player::label() без значения не сработает: методу всегда нужен его self. Если его пропустить, получишь E0061, «this function takes 1 argument but 0 arguments were supplied».
Исправление 3: передай функции то, что ей нужно
Заголовок раздела «Исправление 3: передай функции то, что ей нужно»Выбирай это, когда значения ещё нет или когда функция вообще не в блоке impl.
Классический случай — конструктор. new создаёт значение, так что self, из которого можно читать, нет. Передай new начальные данные обычными параметрами и собери структуру через 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!("Счёт: {}", counter.count);}Вывод:
Счёт: 10Обрати внимание на регистр: Self (с большой S) — это тип, поэтому Self { ... } создаёт новое значение. self (с маленькой s) — это значение, у которого вызвали метод.
Та же идея исправляет и свободную функцию, то есть функцию вне любого блока impl. Там rustc формулирует чуть иначе: «this function can’t have a self parameter» (у этой функции не может быть параметра self). Вместо этого передай структуру по ссылке:
struct Cart { items: Vec<u32>,}
fn total(cart: &Cart) -> u32 { cart.items.iter().sum()}
// вызов: total(&cart)Или перенеси total в impl Cart и дай ей &self, как в исправлении 1. Оба варианта хороши; метод читается естественнее, когда функция явно «про» корзину.
Где это обычно встречается
Заголовок раздела «Где это обычно встречается»Внутри new. Если написать self.count = 0; в fn new() -> Self, получишь E0424, а предложение rustc fn new(&self) -> Self смысла не имеет (чтобы сделать счётчик, понадобился бы счётчик). Исправление: собери значение через Self { count: 0 }, как в исправлении 3.
Внутри замыкания в ассоциированной функции. Проблема не в замыкании, а в функции вокруг него:
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` parameterЭто та же ошибка: у функции sale_prices нет параметра self. Исправление: сделай её методом, fn sale_prices(&self, prices: &[u32]), или передай число параметром, fn sale_prices(prices: &[u32], discount: u32). Подробнее в уроке Замыкания.
В main или во вспомогательной функции. self никогда не работает вне блока impl. Исправление: передай структуру параметром (total(&cart)) или вызови у неё метод (cart.total()).
После «статических» методов C# или Java. Ассоциированная функция без self — это версия статического метода в Rust. Если нужна версия для экземпляра, параметр self придётся добавить самому. Подробнее на странице Rust для разработчиков на C#.
Связанные ошибки
Заголовок раздела «Связанные ошибки»- E0425: обратная оплошность. Ты внутри метода, но написал
countвместоself.count. - E0599: «no method named … found». Часто печатается сразу после E0424, потому что функцию без
selfнельзя вызвать через точку. - E0061: неверное число аргументов, например вызов
Player::label()без значения. - E0596: ты добавил
&self, но метод меняет поле, поэтому нужен&mut self. Присваивание полю в таком случае даёт E0594. - Все ошибки компилятора: полный список страниц с ошибками.
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Внутри impl Player функция fn heal() { self.hp += 10; } даёт E0424. Как лучше всего исправить?
2. Почему fn new() -> Self не может использовать self.name?
3. У Player есть fn label(&self) -> String. Какой вызов означает то же, что hero.label()?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- E0424 — список кодов ошибок Rust (на английском): официальное объяснение этой ошибки с коротким примером.
- Синтаксис метода — книга «Язык программирования Rust» (перевод на русский):
&self,&mut selfиself, а также ассоциированные функции вродеnew. - Методы — Rust на примерах (перевод на русский): запускаемые примеры ассоциированных функций и методов рядом.
- The
selfkeyword — документация стандартной библиотеки (на английском): оба значенияself— получатель метода и текущий модуль. - Associated items — The Rust Reference (на английском): точные правила для методов, получателей и ассоциированных функций.