Ошибка Rust E0560: struct has no field named X (неизвестное поле)
E0560 значит: ты создаёшь структуру через Name { field: value }, и одного из написанных полей в этой структуре нет. Обычно это опечатка, поле, которое переименовали, или поле из другой структуры. rustc часто сам подсказывает правильное имя, так что это одна из самых быстро исправляемых ошибок. (Эта страница входит в серию Ошибки компилятора Rust с объяснениями.)
Сообщение об ошибке
Заголовок раздела «Сообщение об ошибке»error[E0560]: struct `User` has no field named `nmae` --> src/main.rs:9:9 |9 | nmae: String::from("Ferris"), // ❌ typo: the field is `name` | ^^^^ unknown field |help: a field with a similar name exists |9 - nmae: String::from("Ferris"), // ❌ typo: the field is `name`9 + name: String::from("Ferris"), // ❌ typo: the field is `name` |Компилятор говорит: у структуры User нет поля nmae, но есть поле с похожим именем, — и показывает строку с правильным именем. Вот программа, которая выдаёт эту ошибку (комментарий значит «опечатка: поле называется name»):
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { nmae: String::from("Ferris"), // ❌ typo: the field is `name` active: true, }; println!("{}", user.email);}Что это значит
Заголовок раздела «Что это значит»В заголовке названы структура (User) и поле, которое ты написал (nmae). ^^^^ показывает на это поле внутри блока User { ... }. Rust сравнил его со списком полей в struct User и не нашёл совпадения.
Под стрелкой будет одна из трёх подсказок. Каждая говорит о своём:
help: a field with a similar name exists(есть поле с похожим именем): опечатка. rustc показывает строку с правильным именем.note: available fields are: `username`(доступные поля): близкого совпадения нет. Это поля, которые ты ещё не заполнил.note: all struct fields are already assigned(все поля уже заданы): ты заполнил все настоящие поля, а это — лишнее.
Обрати внимание: rustc не жалуется ещё и на то, что name не заполнено. Исправь опечатку — и обе проблемы исчезнут разом.
Это как заполнять бумажную анкету и вписать номер телефона в графу «Факс». В анкете такой графы нет, и сотрудник возвращает её тебе.
Почему Rust так делает
Заголовок раздела «Почему Rust так делает»Поля структуры фиксируются, когда ты пишешь struct User { ... }. Каждый раз, когда ты создаёшь User, Rust проверяет, что ты указал ровно эти поля: ни одного пропущенного, лишнего или написанного с ошибкой. Подробнее — в разделе Объявляем и создаём структуру.
Это ловит настоящие баги. В JavaScript { nmae: "Ferris" } молча создаёт объект с неправильным ключом, и user.name окажется undefined где-нибудь намного позже. В Rust опечатка не пройдёт мимо компилятора, так что у каждого User в твоей программе действительно есть name.
Как исправить
Заголовок раздела «Как исправить»Исправление 1: исправь написание
Заголовок раздела «Исправление 1: исправь написание»Выбирай этот вариант, когда видишь a field with a similar name exists. Возьми имя из строки help:. Имена полей чувствительны к регистру, а в Rust принят snake_case, так что userName и user_name — разные имена.
Следи и за сокращённой инициализацией полей (field init shorthand): User { nmae, email } значит User { nmae: nmae, email: email }, поэтому имя переменной должно совпадать с именем поля. Либо переименуй переменную, либо напиши поле полностью: User { name: nmae, email }.
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), // ✅ настоящее имя поля active: true, }; println!("{} ({}) активен: {}", user.name, user.email, user.active);
// сокращённая запись: имена переменных совпадают с именами полей let name = String::from("Ada"); let other = User { name, email, active: false }; println!("{} ({}) активен: {}", other.name, other.email, other.active);}Вывод:
Ferris ([email protected]) активен: trueAda ([email protected]) активен: falseИсправление 2: возьми новое имя поля или добавь поле
Заголовок раздела «Исправление 2: возьми новое имя поля или добавь поле»Выбирай этот вариант, когда подсказки о похожем имени нет. Часто изменилась сама структура: кто-то переименовал name в username или удалил поле, а этот код всё ещё использует старое. rustc перечисляет, что осталось:
error[E0560]: struct `User` has no field named `name` --> src/main.rs:8:9 |8 | name: String::from("Ferris"), | ^^^^ `User` does not have this field | = note: available fields are: `username`Честных вариантов два. Если права структура, используй её текущее имя поля. Если прав твой код и структуре действительно нужно это поле, добавь его в определение структуры. Здесь Config выдал all struct fields are already assigned для debug, и исправление — добавить debug в структуру:
struct User { username: String, // раньше называлось `name`: используем новое имя email: String,}
struct Config { port: u16, host: String, debug: bool, // добавили в структуру, потому что оно нужно коду}
fn main() { let user = User { username: String::from("ferris"), }; println!("{} ({})", user.username, user.email);
let config = Config { port: 8080, host: String::from("localhost"), debug: true, }; println!("{}:{} debug={}", config.host, config.port, config.debug);}Вывод:
ferris ([email protected])localhost:8080 debug=trueЕсли структура пришла из крейта, который ты только что обновил, поле могли переименовать в новой версии. Посмотри структуру на docs.rs (на английском) для этой версии или список изменений (changelog) крейта. Когда добавляешь поле в свою структуру, каждое место, где она создаётся, тоже должно его заполнить. rustc покажет на каждое такое место ошибкой E0063 (смотри ниже).
Исправление 3: возьми правильную структуру
Заголовок раздела «Исправление 3: возьми правильную структуру»Выбирай этот вариант, когда поле, которое ты написал, существует, но в другой структуре. Когда есть две похожие структуры, например Product с полем title и Customer с полем name, их легко перепутать:
error[E0560]: struct `Product` has no field named `name` --> src/main.rs:13:9 |13 | name: String::from("Keyboard"), | ^^^^ `Product` does not have this field | = note: available fields are: `title`Посмотри на пометку available fields. Если там поля, которых ты не ждал, значит, ты создаёшь не ту структуру. Возьми правильное имя структуры или имя поля той структуры, которую ты имел в виду:
struct Product { title: String, price: u32, // в центах}
struct Customer { name: String, email: String,}
fn main() { let keyboard = Product { title: String::from("Клавиатура"), // у товаров есть `title` price: 4900, }; let buyer = Customer { name: String::from("Аня"), // у покупателей есть `name` }; println!("{} покупает товар «{}» за {} центов", buyer.name, keyboard.title, keyboard.price); println!("Чек отправлен на {}", buyer.email);}Вывод:
Аня покупает товар «Клавиатура» за 4900 центовЧек отправлен на [email protected]Исправление 4: круглые скобки для кортежной структуры
Заголовок раздела «Исправление 4: круглые скобки для кортежной структуры»Выбирай этот вариант, когда структура — кортежная (tuple struct), например struct Point(i32, i32);. У её полей нет имён, поэтому Point { x: 1, y: 2 } даёт E0560 и для x, и для y, с подсказкой help: `Point` is a tuple struct, use the appropriate syntax и предложением Point(/* i32 */, /* i32 */). Создавай её с круглыми скобками, Point(1, 2), а читай через .0 и .1. Если тебе удобнее имена, поменяй определение на struct Point { x: i32, y: i32 }. Смотри урок Кортежи — там есть совет, когда выбирать кортеж, а когда структуру.
Обратная ситуация: E0063 missing field
Заголовок раздела «Обратная ситуация: E0063 missing field»Близнец E0560 — E0063: поле, которое у структуры есть, но ты его не заполнил. Rust никогда не заполняет поля за тебя, так что каждому полю нужно значение:
error[E0063]: missing field `active` in initializer of `User` --> src/main.rs:8:16 |8 | let user = User { | ^^^^ missing `active`Если не хватает нескольких полей, перечисляются все: missing fields `active`, `email` and `login_count` in initializer of `User`. Исправление: дай значение каждому полю. Если у многих полей есть разумные значения по умолчанию, выведи (derive) Default и заполни остальное синтаксисом обновления структуры ..:
#[derive(Debug, Default)]struct Settings { volume: u8, dark_mode: bool, language: String,}
fn main() { // все поля написаны явно let full = Settings { volume: 80, dark_mode: false, language: String::from("en") };
// только нужные поля, остальное — из Default let quick = Settings { dark_mode: true, ..Default::default() };
// остальное копируем из другого значения let louder = Settings { volume: 100, ..full };
println!("{:?}", quick); println!("{:?}", louder);}Вывод:
Settings { volume: 0, dark_mode: true, language: "" }Settings { volume: 100, dark_mode: false, language: "en" }Значение по умолчанию для числа — 0, для bool — false, а для String — пустая строка. Если нужны другие значения по умолчанию, напиши impl Default for Settings сам. Смотри Default: разумное начальное значение.
Где это обычно встречается
Заголовок раздела «Где это обычно встречается»Внутри синтаксиса обновления ... Settings { dark: true, ..defaults } тоже даёт E0560. Здесь пометка перечисляет все поля (available fields are: `volume`, `dark_mode`, `language`), а подсказки о похожем имени может не быть, если имена слишком разные. Исправление: dark_mode: true.
Варианты перечисления с именованными полями. Для enum Shape { Circle { radius: f64 } } запись Shape::Circle { r: 2.0 } — та же ошибка, но rustc выдаёт другой код: E0559, variant `Shape::Circle` has no field named `r`, с той же пометкой available fields и подсказками об опечатках. Исправление: Shape::Circle { radius: 2.0 }. Смотри Перечисления могут хранить данные.
Структура из другого модуля. Если поле существует, но не pub, вместо этого получишь E0451, «field balance of struct Account is private». Исправление: используй конструктор модуля, например Account::new(...). Смотри Всё по умолчанию приватное.
Связанные ошибки
Заголовок раздела «Связанные ошибки»- E0609: no field
xon typeT: та же опечатка, но при чтении поля (user.nmae), а не при создании структуры. - E0451: field is private in struct literal: поле существует, но отсюда его задать нельзя.
- E0308: mismatched types: имя поля верное, но у значения не тот тип, например
"Ferris"для поля типаString. E0063: missing field in initializer: поле, которое ты забыл (смотри выше).E0559: variant has no field named x: E0560 для вариантов перечисления.- Все ошибки компилятора с объяснениями
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. rustc пишет note: all struct fields are already assigned. Что это значит?
2. У тебя есть let nmae = ...;, и ты пишешь User { nmae, email }. Как исправить?
3. Какую ошибку ты получишь, если пропустишь поле, например User { name, email } без active?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- E0560 — Rust error codes index (на английском): официальное объяснение этой ошибки.
- Определение и создание экземпляров структур — книга «Язык программирования Rust» (перевод на русский): литералы структур, сокращённая инициализация полей, синтаксис обновления и кортежные структуры.
- E0063 — Rust error codes index (на английском): официальная страница о «близнеце» этой ошибки — пропущенном поле.
- Struct expressions — The Rust Reference (на английском): точные правила для
Name { field: value }, сокращённой записи и..base. Default— стандартная библиотека Rust (на английском): как работают#[derive(Default)]и..Default::default().