Ошибка 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», где ты написал «Нестандартный». Такой вариант существует, но рядом нужно заполнить размеры.
Почему Rust так делает
Заголовок раздела «Почему Rust так делает»У вариантов перечисления три формы, и каждая пишется по-своему — и когда ты её создаёшь, и когда сопоставляешь с образцом (см. урок Перечисления):
| Вариант | Создать | Сопоставить |
|---|---|---|
Единичный: 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 field8 + 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 } =>.
Связанные ошибки
Заголовок раздела «Связанные ошибки»- E0559: variant has no field named x: фигурные скобки на месте, но имя поля внутри них неверное.
- E0026: struct or variant does not have a field named x: неверное имя поля внутри фигурных скобок образца.
- E0027: pattern does not mention field x: в образце со скобками пропущены поля; добавь
... - E0004: non-exhaustive patterns: после исправления веток
matchвсё равно должен покрывать каждый вариант. E0532: expected unit struct, unit variant or constant, found tuple variant: версия для кортежного варианта (см. выше).- Все ошибки компилятора с объяснениями
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Для enum Shape { Circle { radius: f64 } } какая ветка match скомпилируется?
2. let s = Shape::Circle(2.0); даёт «expected value, found struct variant». Как это исправить?
3. Что из этого можно использовать само по себе как образец в match?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- E0533 — Rust error codes index (на английском): официальное объяснение этой ошибки.
- Синтаксис шаблонов — книга «Язык программирования Rust» (перевод на русский): деструктуризация перечислений, пропуск значений через
..и охранные условия. - Перечисления — Rust на примерах (перевод на русский): единичные, кортежные и структурные варианты в одном
match. - E0532 — Rust error codes index (на английском): официальная страница о версии этой ошибки для кортежных вариантов.
- Patterns — The Rust Reference (на английском): какие пути можно использовать как образцы и правила для структурных и кортежных образцов.