Ошибка Rust E0532: expected unit struct, unit variant or constant, found tuple variant
E0532 значит: форма твоего образца не совпадает с формой того, что ты назвал. Классический случай — ветка match вроде Shape::Circle => для варианта с данными, Circle(f64). Rust хочет круглые скобки: Shape::Circle(_). Обратная ошибка получает тот же код, но с другой формулировкой, «expected tuple struct or tuple variant»: круглые скобки после того, у чего нет данных в круглых скобках, например Status::Active(). Оба случая исправляются одной строкой. (Эта страница входит в раздел Ошибки компилятора Rust с объяснениями.)
Сообщение об ошибке
Заголовок раздела «Сообщение об ошибке»error[E0532]: expected unit struct, unit variant or constant, found tuple variant `Shape::Circle` --> src/main.rs:8:9 |2 | Circle(f64), | ----------- `Shape::Circle` defined here...8 | Shape::Circle => "circle", // ❌ `Circle` holds a value | ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Shape::Circle(_)`По-русски: «ожидалась единичная структура, единичный вариант или константа, а найден кортежный вариант Shape::Circle». help сразу предлагает синтаксис образца для кортежного варианта: Shape::Circle(_).
Вот программа, которая её вызывает (комментарий // ❌ оставлен на английском, потому что rustc цитирует эту строку; он значит «Circle хранит значение»):
enum Shape { Circle(f64), Square(f64),}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "circle", // ❌ `Circle` holds a value Shape::Square(_) => "square", }}
fn main() { println!("{}", name(&Shape::Circle(1.0)));}Что это значит
Заголовок раздела «Что это значит»^^^ указывает на Shape::Circle в строке 8, а --- в строке 2 показывает, как он определён: Circle(f64) — кортежный вариант (tuple variant), который несёт одно f64. Образец, который состоит только из имени и после которого ничего нет, должен быть чем-то одним из трёх:
- единичной структурой (unit struct), например
struct Empty; - единичным вариантом (unit variant) — вариантом без данных, например
Shape::EmptyилиNone - константой, например
const LIMIT: u32 = 100;
Shape::Circle — ни то, ни другое, ни третье. Строка help сразу даёт исправление: Shape::Circle(_), то есть «круг с любым значением».
Второй заголовок E0532 — зеркальное отражение первого: expected tuple struct or tuple variant, found unit variant `Status::Active` (или found struct, или found constant). Там уже ты поставил круглые скобки после имени, а то, что ты назвал, значений в круглых скобках не принимает.
Это как анкета с пунктом «Питомец: собака (кличка: ____)». Если написать просто «собака», поле для клички останется пустым. А если написать «рыбка (кличка: Пузырь)» там, где в анкете «рыбка» без поля, ты добавишь поле, которого нет.
Почему Rust так делает
Заголовок раздела «Почему Rust так делает»У каждой структуры и каждого варианта перечисления одна из трёх форм, и пишется она одинаково и при создании, и при сопоставлении с образцом (см. урок Перечисления):
| Вид | Создать | Сопоставить |
|---|---|---|
Единичный: Empty |
Shape::Empty |
Shape::Empty |
Кортежный: Circle(f64) |
Shape::Circle(1.0) |
Shape::Circle(r) или Shape::Circle(..) |
Структурный: Rect { w: f64, h: f64 } |
Shape::Rect { w: 2.0, h: 3.0 } |
Shape::Rect { w, h } или Shape::Rect { .. } |
Раз формы строгие, образец всегда выглядит как значение, с которым он совпадает, и по match видно, какие данные есть в каждой ветке. Это помогает и при изменении типа: если Empty позже получит значение и станет Empty(u32), каждая старая ветка Shape::Empty будет отмечена, вместо того чтобы тихо совпадать с чем-то новым.
Как исправить
Заголовок раздела «Как исправить»Исправление 1: Добавь (_), (..) или имена для значений
Заголовок раздела «Исправление 1: Добавь (_), (..) или имена для значений»Выбирай этот вариант, когда в сообщении написано found tuple variant или found tuple struct — это самая частая E0532. Пиши _ для каждого ненужного значения, .., чтобы пропустить все сразу, или имя, если значение тебе нужно:
enum Shape { Circle(f64), Rect(f64, f64), Empty,}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle(_) => "круг", // ✅ одно поле, пропущено Shape::Rect(..) => "прямоугольник", // ✅ сколько угодно полей, все пропущены Shape::Empty => "ничего", // единичный вариант: без скобок }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ привязываем поле, потому что оно нужно Shape::Rect(w, h) => w * h, Shape::Empty => 0.0, }}
fn main() { let shapes = [Shape::Circle(1.0), Shape::Rect(2.0, 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прямоугольник: 6.00ничего: 0.00кругов: 1(..) удобен для вариантов с несколькими значениями и продолжит работать, если ты позже добавишь ещё одно. Подробнее — в уроке Сопоставление с образцом.
Исправление 2: Убери () у единичного варианта
Заголовок раздела «Исправление 2: Убери () у единичного варианта»Выбирай этот вариант, когда в сообщении написано found unit variant или found unit struct. У варианта нет данных, поэтому в скобки класть нечего:
error[E0532]: expected tuple struct or tuple variant, found unit variant `Status::Active` --> src/main.rs:8:9 |2 | Active, | ------ `Status::Active` defined here...8 | Status::Active() => "active", // ❌ `Active` holds no data | ^^^^^^^^^^^^^^^^ help: use this syntax instead: `Status::Active`rustc пишет, что ожидал кортежную структуру или кортежный вариант, а нашёл единичный вариант, и предлагает писать просто Status::Active. Программа, которая к этому приводит (комментарий значит «у Active нет данных»):
enum Status { Active, Banned(String),}
fn label(s: &Status) -> &'static str { match s { Status::Active() => "active", // ❌ `Active` holds no data Status::Banned(_) => "banned", }}
fn main() { println!("{}", label(&Status::Active));}Пиши только имя — и в образце, и там, где создаёшь значение:
#[derive(Debug)]enum Status { Active, Banned(String),}
fn label(s: &Status) -> String { match s { Status::Active => String::from("активен"), // ✅ единичный вариант: без () Status::Banned(reason) => format!("заблокирован ({})", reason), }}
fn main() { println!("{}", label(&Status::Active)); println!("{}", label(&Status::Banned(String::from("спам")))); let s = Status::Active; // ✅ и при создании тоже без () println!("{:?}", s);}Вывод:
активензаблокирован (спам)ActiveЕсли ты хотел, чтобы вариант нёс данные, измени определение: например, Active(u64) для метки времени «с какого момента», и тогда правильным образцом будет Status::Active(_).
Исправление 3: Используй фигурные скобки для структуры с именованными полями
Заголовок раздела «Исправление 3: Используй фигурные скобки для структуры с именованными полями»Выбирай этот вариант, когда в сообщении написано found struct. Структура с именованными полями, struct Point { x: i32, y: i32 }, разбирается фигурными скобками и именами полей, а не круглыми скобками:
error[E0532]: expected tuple struct or tuple variant, found struct `Point` --> src/main.rs:8:9 |1 | / struct Point {2 | | x: i32,3 | | y: i32,4 | | } | |_- `Point` defined here...8 | let Point(x, y) = p; // ❌ `Point` has named fields | ^^^^^^^^^^^ help: use struct pattern syntax instead: `Point { x, y }`Программа, которая к этому приводит (комментарий значит «у Point именованные поля»):
struct Point { x: i32, y: i32,}
fn main() { let p = Point { x: 3, y: 4 }; let Point(x, y) = p; // ❌ `Point` has named fields println!("{} {}", x, y);}Подсказка rustc Point { x, y } абсолютно верна. Пиши поле: имя, если хочешь другое имя переменной:
struct Point { x: i32, y: i32,}
struct Meters(f64); // кортежная структура: здесь круглые скобки правильные
fn main() { let p = Point { x: 3, y: 4 }; let Point { x, y } = p; // ✅ фигурные скобки и имена полей println!("x = {}, y = {}", x, y);
let q = Point { x: -1, y: 7 }; let Point { x: left, y: up } = q; // ✅ переименование при разборе println!("left = {}, up = {}", left, up);
let Meters(m) = Meters(2.5); // ✅ кортежная структура, кортежный образец println!("{} м", m);}Вывод:
x = 3, y = 4left = -1, up = 72.5 мДля варианта перечисления с именованными полями, Shape::Rect(w, h) для Rect { w: f64, h: f64 }, та же ошибка даёт другой код — E0164. Исправление то же: фигурные скобки.
Исправление 4: Используй константу или охранное условие вместо вызова функции
Заголовок раздела «Исправление 4: Используй константу или охранное условие вместо вызова функции»Выбирай этот вариант, когда в сообщении написано expected a pattern, found a function call («ожидался образец, найден вызов функции»). Образец должен быть известен на этапе компиляции, а вызов функции таким не является:
error[E0532]: expected a pattern, found a function call --> src/main.rs:7:14 |7 | Some(limit()) => "full", // ❌ a function call can't be a pattern | ^^^^^ not a tuple struct or tuple variant | = note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>Программа, которая к этому приводит (комментарий значит «вызов функции не может быть образцом»):
fn limit() -> u32 { 100}
fn status(users: Option<u32>) -> &'static str { match users { Some(limit()) => "full", // ❌ a function call can't be a pattern Some(_) => "open", None => "closed", }}
fn main() { println!("{}", status(Some(100)));}Если значение никогда не меняется, сделай его const: константы можно использовать внутри образцов. Если его нужно вычислять, привяжи значение к имени и сравни в охранном условии (match guard):
const LIMIT: u32 = 100; // константу можно использовать внутри образца
fn limit_for(premium: bool) -> u32 { if premium { 500 } else { 100 }}
fn status(users: Option<u32>) -> &'static str { match users { Some(LIMIT) => "мест нет", // ✅ константа Some(_) => "открыто", None => "закрыто", }}
fn status_for(users: Option<u32>, premium: bool) -> &'static str { match users { Some(n) if n >= limit_for(premium) => "мест нет", // ✅ вызов функции в охранном условии Some(_) => "открыто", None => "закрыто", }}
fn main() { println!("{}", status(Some(100))); println!("{}", status(Some(42))); println!("{}", status(None)); println!("{}", status_for(Some(100), false)); println!("{}", status_for(Some(100), true));}Вывод:
мест нетоткрытозакрытомест нетоткрытоОхранные условия объясняются в уроке Сопоставление с образцом.
Где это обычно встречается
Заголовок раздела «Где это обычно встречается»Единичный вариант получил значение. Раньше Event::Logout был единичным вариантом, а ты превратил его в Logout(u64). Теперь каждая ветка Event::Logout => даёт E0532. Исправление: Event::Logout(_) => или Event::Logout(at) =>, если значение нужно.
Проверка только вида значения. Если ты пришёл из Java или TypeScript, то можешь написать if let Shape::Circle = shape, чтобы спросить «это круг?». Пиши if let Shape::Circle(_) = shape или matches!(shape, Shape::Circle(_)), если нужен быстрый bool.
Без префикса Shape:: это E0530. Если написать голое имя, например Ok => или Circle => после use Shape::*;, rustc прочитает его как новую переменную. Он сообщит E0530, match bindings cannot shadow tuple variants, с подсказкой try specify the pattern arguments: `Ok(..)` . Исправление то же: добавь круглые скобки.
Связанные ошибки
Заголовок раздела «Связанные ошибки»- E0533: expected unit struct, unit variant or constant, found struct variant: та же ошибка для вариантов с именованными полями; добавь
{ .. }. - E0164: expected tuple struct or tuple variant, found struct variant: круглые скобки у варианта с именованными полями или у ассоциированной константы либо функции.
- E0023: wrong number of fields in a tuple pattern (на английском): круглые скобки на месте, но имён внутри слишком много или слишком мало.
- E0026: struct or variant does not have a field named x: неверное имя поля внутри фигурных скобок образца.
- E0004: non-exhaustive patterns: после исправления веток
matchвсё равно должен покрывать каждый вариант. - Все ошибки компилятора с объяснениями
Проверь себя
Заголовок раздела «Проверь себя»Проверь себя
1. Для enum Shape { Circle(f64), Empty } какая ветка match скомпилируется?
2. rustc пишет «expected tuple struct or tuple variant, found unit variant Status::Active». Как это исправить?
3. struct Point { x: i32, y: i32 }: как разобрать её через let?
Результат: 0 / 3
Что почитать
Заголовок раздела «Что почитать»- E0532 — Rust error codes index (на английском): официальное объяснение этой ошибки.
- Синтаксис шаблонов — книга «Язык программирования Rust» (перевод на русский): разбор структур и перечислений, пропуск значений через
_и..и охранные условия. - Перечисления — Rust на примерах (перевод на русский): единичные и кортежные варианты рядом.
- Структуры — Rust на примерах (перевод на русский): фигурные скобки для именованных полей, круглые — для кортежных структур.
- Patterns — The Rust Reference (на английском): точные правила для образцов-путей, кортежных и структурных образцов.