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

Ошибка Rust E0533: expected unit struct, unit variant or constant, found struct variant

E0533 значит: ты написал имя вроде Shape::Circle само по себе, а в этом месте одного имени мало. Чаще всего это вариант перечисления с именованными полями (Circle { radius: f64 }), у которого забыли { }, — в ветке match или при создании значения. Реже это функция или метод там, где может стоять только фиксированное значение. Оба случая исправляются быстро, как только понимаешь, чего хочет rustc. (Эта страница входит в раздел Ошибки компилятора Rust с объяснениями.)

error[E0533]: expected unit struct, unit variant or constant, found struct variant `Shape::Circle`
--> src/main.rs:8:9
|
8 | Shape::Circle => "circle", // ❌ `Circle` has a field
| ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
help: the struct variant's field is being ignored
|
8 | Shape::Circle { radius: _ } => "circle", // ❌ `Circle` has a field
| +++++++++++++

По-русски: «ожидалась единичная структура, единичный вариант или константа, а найден структурный вариант Shape::Circle». Строка help показывает, как явно пропустить поле варианта.

Вот программа, которая её вызывает (комментарий // ❌ оставлен на английском, потому что rustc цитирует эту строку целиком; он значит «у Circle есть поле»):

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle => "circle", // ❌ `Circle` has a field
Shape::Square { .. } => "square",
}
}
fn main() {
println!("{}", name(&Shape::Square { side: 2.0 }));
}

^^^ указывает на Shape::Circle, а заголовок объясняет, что здесь было разрешено. Образец, который состоит только из имени, должен быть чем-то одним из трёх:

  • единичной структурой (unit struct), например struct Empty;
  • единичным вариантом (unit variant) — вариантом без данных, например Shape::Empty или None
  • константой, например const MAX: u32 = 100;

Shape::Circle — ни то, ни другое, ни третье. Это структурный вариант (struct variant): у него есть поле radius. Голое Shape::Circle совпадало бы с «каким-то кругом», но ничего не говорило бы о его поле, а Rust хочет, чтобы форма образца совпадала с формой варианта. Строка help: показывает исправление: добавь фигурные скобки.

Вторая разновидность E0533 звучит как expected value, found struct variant («ожидалось значение, найден структурный вариант»). Та же путаница, но при создании значения — обычно с круглыми скобками, например Shape::Circle(2.0).

Это как бланк посылки с полем «Размер: S, M или L», где ты написал «Нестандартный». Такой вариант существует, но рядом нужно заполнить размеры.

У вариантов перечисления три формы, и каждая пишется по-своему — и когда ты её создаёшь, и когда сопоставляешь с образцом (см. урок Перечисления):

Вариант Создать Сопоставить
Единичный: Empty Shape::Empty Shape::Empty
Кортежный: Point(f64, f64) Shape::Point(1.0, 2.0) Shape::Point(x, y) или Shape::Point(..)
Структурный: Circle { radius: f64 } Shape::Circle { radius: 2.0 } Shape::Circle { radius } или Shape::Circle { .. }

Строгие формы значат, что образец всегда выглядит как то, с чем он совпадает. Читая match, ты точно знаешь, какие данные есть в каждой ветке. А ещё, когда вариант меняет форму (например, Empty получает поле), компилятор отметит каждое место со старой формой, вместо того чтобы молча делать что-то не то.

Исправление 1: Добавь в образец { .. } или поля

Заголовок раздела «Исправление 1: Добавь в образец { .. } или поля»

Выбирай этот вариант, когда ошибка указывает на ветку match, if let или matches! и пишет found struct variant. Пиши { .. }, если поля тебе не нужны, или перечисли их, если нужны. Подсказка rustc { radius: _ } тоже работает, а { .. } — просто более короткий способ сказать то же самое.

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
Empty,
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "круг", // ✅ «круг любого радиуса»
Shape::Square { .. } => "квадрат",
Shape::Empty => "ничего", // единичный вариант: скобки не нужны
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ поля названы, потому что они нужны
Shape::Square { side } => side * side,
Shape::Empty => 0.0,
}
}
fn main() {
let shapes = [Shape::Circle { radius: 1.0 }, Shape::Square { side: 3.0 }, Shape::Empty];
for shape in &shapes {
println!("{}: {:.2}", name(shape), area(shape));
}
let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle { .. })).count();
println!("кругов: {}", circles);
}

Вывод:

круг: 3.14
квадрат: 9.00
ничего: 0.00
кругов: 1
▶ Попробуй сам

{ .. } подходит для любого структурного варианта, сколько бы полей у него ни было. Для кортежных вариантов та же идея пишется как (..). Подробнее — в уроке Сопоставление с образцом.

Исправление 2: Создавай значение с фигурными скобками и именами полей

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

Выбирай этот вариант, когда сообщение звучит как expected value, found struct variant. Ты создаёшь структурный вариант так, будто это кортежный (или вообще без полей):

error[E0533]: expected value, found struct variant `Shape::Circle`
--> src/main.rs:8:17
|
8 | let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field
| ^^^^^^^^^^^^^ not a value
|
help: you might have meant to create a new value of the struct
|
8 - let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field
8 + let shape = Shape::Circle { radius: /* value */ }; // ❌ `Circle` has a named field
|

rustc пишет «это не значение» и предлагает создать значение с полем по имени. Вот программа, из-за которой появляется ошибка:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn main() {
let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field
println!("{:?}", shape);
}

/* value */ в подсказке — это место для твоего значения. Поля структурного варианта задаются по имени, внутри фигурных скобок:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
impl Shape {
// короткий конструктор, если хочется писать `Shape::circle(2.0)`
fn circle(radius: f64) -> Shape {
Shape::Circle { radius }
}
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // ✅ фигурные скобки и имя поля
let b = Shape::Square { side: 1.5 };
let c = Shape::circle(0.5);
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}

Вывод:

Circle { radius: 2.0 }
Square { side: 1.5 }
Circle { radius: 0.5 }
▶ Попробуй сам

Если тебе больше нравится Shape::Circle(2.0), сделай вариант кортежным: Circle(f64). Для одного очевидного поля это хороший выбор, а когда полей несколько, именованные понятнее.

Исправление 3: Используй константу или охранное условие вместо функции

Заголовок раздела «Исправление 3: Используй константу или охранное условие вместо функции»

Выбирай этот вариант, когда сообщение пишет found associated function («найдена ассоциированная функция»). Так бывает и с методами, например String::len. Образец должен быть значением, известным на этапе компиляции. Вызов функции таким не является, поэтому имя функции не может быть образцом:

error[E0533]: expected unit struct, unit variant or constant, found associated function `Limits::max_users`
--> src/main.rs:12:9
|
12 | Limits::max_users => "full", // ❌ a function can't be a pattern
| ^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant

Программа, которая к этому приводит (комментарий значит «функция не может быть образцом»):

struct Limits;
impl Limits {
fn max_users() -> u32 {
100
}
}
fn status(users: u32) -> &'static str {
match users {
0 => "empty",
Limits::max_users => "full", // ❌ a function can't be a pattern
_ => "open",
}
}
fn main() {
println!("{}", status(100));
}

Если значение никогда не меняется, сделай его const. Константы могут быть образцами. Если его нужно вычислять, оставь функцию и сравнивай в охранном условии (match guard) с if:

struct Limits;
impl Limits {
const MAX_USERS: u32 = 100; // константу можно использовать как образец
fn max_rooms(premium: bool) -> u32 {
if premium { 20 } else { 5 }
}
}
fn status(users: u32) -> &'static str {
match users {
0 => "пусто",
Limits::MAX_USERS => "мест нет", // ✅ константа
_ => "открыто",
}
}
fn rooms_status(rooms: u32, premium: bool) -> &'static str {
match rooms {
n if n >= Limits::max_rooms(premium) => "больше комнат нельзя", // ✅ вызов в охранном условии
_ => "можно добавить комнату",
}
}
fn main() {
println!("{}", status(0));
println!("{}", status(100));
println!("{}", status(42));
println!("{}", rooms_status(5, false));
println!("{}", rooms_status(5, true));
}

Вывод:

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

Охранные условия объясняются в уроке Сопоставление с образцом.

Единичный вариант получил поля. Раньше Status::Done был единичным вариантом, а ты превратил его в Done { at: u64 }. Теперь каждая ветка Status::Done => и каждое let s = Status::Done; дают E0533. Исправление: Status::Done { .. } => в образцах и Status::Done { at: 0 } (с настоящим значением) там, где значение создаётся.

Привычки из другого языка. В Java или TypeScript можно написать case Circle:, чтобы проверить только вид значения. В Rust пиши Shape::Circle { .. } => или matches!(shape, Shape::Circle { .. }), если нужен быстрый bool.

Версия для кортежного варианта. Для кортежного варианта вроде Circle(f64) голая ветка Shape::Circle => даёт другой код, E0532, с тем же заголовком: «expected unit struct, unit variant or constant, found tuple variant Shape::Circle». Исправление — Shape::Circle(_) или Shape::Circle(..). А круглые скобки у структурного варианта в образце, например Shape::Circle(r) => для Circle { radius: f64 }, дают E0164: «expected tuple struct or tuple variant, found struct variant». Исправление: Shape::Circle { radius: r } =>.

Проверь себя

1. Для enum Shape { Circle { radius: f64 } } какая ветка match скомпилируется?

2. let s = Shape::Circle(2.0); даёт «expected value, found struct variant». Как это исправить?

3. Что из этого можно использовать само по себе как образец в match?

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