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

Ошибка Rust E0026: struct or variant does not have a field named X (поле в образце)

E0026 значит: ты разбираешь структуру или вариант перечисления в образце, например Shape::Circle { r }, и одного из написанных имён полей не существует. Это версия E0560 и E0559 для образцов: те ловят ту же ошибку, когда ты создаёшь значение. Обычно rustc называет правильное имя в строке help:, так что исправление — часто одно слово. (Эта страница входит в серию Ошибки компилятора Rust с объяснениями.)

error[E0026]: variant `Shape::Circle` does not have a field named `r`
--> src/main.rs:8:25
|
8 | Shape::Circle { r } => 3.14 * r * r, // ❌ the field is called `radius`
| ^
| |
| variant `Shape::Circle` does not have this field
| help: `Shape::Circle` has a field named `radius`

Компилятор говорит: у варианта Shape::Circle нет поля r, зато есть поле radius. Вот программа, которая выдаёт эту ошибку (комментарий значит «поле называется radius»):

enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { r } => 3.14 * r * r, // ❌ the field is called `radius`
Shape::Rectangle { width, height } => width * height,
}
}
fn main() {
println!("{}", area(&Shape::Circle { radius: 1.0 }));
}

Для той же строки ты увидишь и вторую ошибку: E0027, «pattern does not mention field radius» (образец не упоминает поле radius). Это та же ошибка, увиденная с другой стороны. Rust нашёл поле, которое ты назвал, но которого нет (r), и настоящее поле, которое ты не назвал (radius). Исправь имя — и обе ошибки исчезнут.

В заголовке названы структура или вариант, с которым ты сопоставляешь (Shape::Circle), и поле, которое ты написал (r). ^ показывает на это имя внутри фигурных скобок образца.

В образце имена внутри { } — это имена полей, а не новые имена переменных, которые ты выбираешь сам. Shape::Circle { r } — сокращение от Shape::Circle { r: r }: «возьми поле с именем r и положи его в переменную с именем r». У Circle нет поля r, поэтому Rust останавливается.

Под стрелкой rustc даёт одну из этих подсказок:

  • help: `Shape::Circle` has a field named `radius` (у Shape::Circle есть поле radius): ты не упомянул ровно одно поле, и rustc догадывается, что ты имел в виду его.
  • help: a field with a similar name exists (есть поле с похожим именем): опечатка, например nmae вместо name. rustc показывает исправленную строку.
  • Никакой подсказки: rustc не смог догадаться. Посмотри настоящие имена в определении структуры или перечисления.

Это как попросить библиотекаря «книгу с полки под названием Почти-фантастика». Он понимает, что тебе нужна какая-то полка, но подойти может только к тем полкам, которые действительно существуют.

Образец вроде Shape::Circle { radius } — это обещание: «когда значение — Circle, дай мне его radius». При компиляции Rust сверяет это обещание с определением, так что образец никогда не сможет запросить данные, которых нет. Смотри Деструктуризация кортежей и структур.

В языках без такой проверки чтение несуществующего ключа даёт undefined или null, и баг проявляется намного позже, далеко от опечатки. В Rust опечатка не пройдёт мимо компилятора. Это защищает и тогда, когда кто-то переименовывает поле: каждый образец, который всё ещё использует старое имя, загорается ошибкой E0026, так что ни один не будет тихо забыт.

Выбирай этот вариант в большинстве случаев. Возьми имя из строки help: или посмотри определение. Имена полей чувствительны к регистру и пишутся в snake_case.

Для опечатки будет подсказка о похожем имени и исправленная строка:

error[E0026]: struct `User` does not have a field named `nmae`
--> src/main.rs:8:16
|
8 | let User { nmae, age } = user; // ❌ typo: the field is `name`
| ^^^^ struct `User` does not have this field
|
help: a field with a similar name exists
|
8 - let User { nmae, age } = user; // ❌ typo: the field is `name`
8 + let User { name, age } = user; // ❌ typo: the field is `name`
|

Программа, которая за ней стоит (комментарий значит «опечатка: поле называется name»):

struct User {
name: String,
age: u32,
}
fn main() {
let user = User { name: String::from("Ferris"), age: 7 };
let User { nmae, age } = user; // ❌ typo: the field is `name`
println!("{} is {} years old", nmae, age);
}

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

struct User {
name: String,
age: u32,
}
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ настоящее имя поля
Shape::Rectangle { width, height } => width * height,
}
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 },
Shape::Rectangle { width: 3.0, height: 4.0 },
];
for shape in &shapes {
println!("площадь: {:.2}", area(shape));
}
let user = User { name: String::from("Ferris"), age: 7 };
let User { name, age } = user; // ✅ `name`, а не `nmae`
println!("{}: {} лет", name, age);
}

Вывод:

площадь: 12.56
площадь: 12.00
Ferris: 7 лет
▶ Попробуй сам

Исправление 2: оставь своё имя переменной через field: name

Заголовок раздела «Исправление 2: оставь своё имя переменной через field: name»

Выбирай этот вариант, когда тебе нравится короткое имя r и ты просто хочешь, чтобы переменная так называлась. Напиши настоящее имя поля, двоеточие, а потом имя переменной: Shape::Circle { radius: r }. Читай это как «возьми поле radius и назови его r».

enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius: r } => 3.14 * r * r, // ✅ поле `radius`, переменная `r`
Shape::Rectangle { width: w, height: h } => w * h,
}
}
fn main() {
let small = Shape::Circle { radius: 1.0 };
let wide = Shape::Rectangle { width: 10.0, height: 2.5 };
println!("маленький круг: {:.2}", area(&small));
println!("широкий прямоугольник: {:.2}", area(&wide));
}

Вывод:

маленький круг: 3.14
широкий прямоугольник: 25.00
▶ Попробуй сам

Это удобно и тогда, когда поля иначе совпали бы по имени с уже существующими переменными или когда имя поля длинное.

Исправление 3: проверь, тот ли вариант ты сопоставляешь

Заголовок раздела «Исправление 3: проверь, тот ли вариант ты сопоставляешь»

Выбирай этот вариант, когда поле, которое ты написал, настоящее, но в другом варианте. У каждого варианта перечисления свои поля. Здесь x принадлежит Click, а ветка сопоставляет KeyPress:

error[E0026]: variant `Event::KeyPress` does not have a field named `x`
--> src/main.rs:9:27
|
9 | Event::KeyPress { x, .. } => format!("key at {}", x), // ❌ `x` belongs to `Click`
| ^
| |
| variant `Event::KeyPress` does not have this field
| help: `Event::KeyPress` has a field named `key`

Программа, которая за ней стоит (комментарий значит «x принадлежит Click»):

enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn describe(event: &Event) -> String {
match event {
Event::Click { x, y } => format!("click at ({}, {})", x, y),
Event::KeyPress { x, .. } => format!("key at {}", x), // ❌ `x` belongs to `Click`
}
}
fn main() {
println!("{}", describe(&Event::KeyPress { key: 'a' }));
}

Догадка rustc (key) — это просто «единственное поле, которое ты не упомянул», так что не принимай её вслепую. Спроси себя, что должна делать эта ветка. У нажатия клавиши нет координат, так что здесь правильное исправление — использовать поле, которое у KeyPress действительно есть:

enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn describe(event: &Event) -> String {
match event {
Event::Click { x, y } => format!("клик в точке ({}, {})", x, y),
Event::KeyPress { key } => format!("нажата клавиша '{}'", key), // ✅ у KeyPress есть `key`
}
}
fn main() {
let events = [Event::Click { x: 10, y: 20 }, Event::KeyPress { key: 'a' }];
for event in &events {
println!("{}", describe(event));
}
}

Вывод:

клик в точке (10, 20)
нажата клавиша 'a'
▶ Попробуй сам

Если у нажатия клавиши действительно должны быть координаты, добавь поля в вариант: KeyPress { key: char, x: i32, y: i32 }. Тогда каждое место, где создаётся KeyPress, тоже должно их заполнить (rustc покажет на каждое ошибкой E0063).

После переименования поля. Ты переименовал в перечислении r в radius, и каждая ветка Shape::Circle { r } => ... теперь даёт E0026. Найди по проекту старое имя и обнови каждый образец или напиши radius: r, чтобы оставить старое имя переменной.

В if let и let. if let Some(User { nmae, .. }) = find_user() даёт ту же ошибку. .. здесь не поможет: .. пропускает поля, которые ты не называешь, но каждое имя, которое ты пишешь, всё равно должно существовать. Исправление: User { name, .. }.

Фигурные скобки у кортежного варианта или кортежной структуры. Для struct Point(i32, i32); в образце Point { x, y } нет настоящих имён полей, с которыми можно сопоставить. rustc сообщает об этом другим кодом, E0769, «tuple variant Point written as struct variant», и предлагает Point(x, y). Смотри Деструктуризация перечислений с данными.

Проверь себя

1. Что запрашивает образец Shape::Circle { r } для enum Shape { Circle { radius: f64 } }?

2. Ты хочешь получить поле radius в переменной r. Какой образец сработает?

3. Скомпилируется ли User { nmae, .. }, если поле называется name?

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