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

Ошибка 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). Там уже ты поставил круглые скобки после имени, а то, что ты назвал, значений в круглых скобках не принимает.

Это как анкета с пунктом «Питомец: собака (кличка: ____)». Если написать просто «собака», поле для клички останется пустым. А если написать «рыбка (кличка: Пузырь)» там, где в анкете «рыбка» без поля, ты добавишь поле, которого нет.

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

Вид Создать Сопоставить
Единичный: 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 = 4
left = -1, up = 7
2.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(..)` . Исправление то же: добавь круглые скобки.

Проверь себя

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