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

Ошибка Rust E0530: match bindings cannot shadow tuple variants (имя уже занято)

E0530 значит: имя в твоём образце уже занято. Ты написал простое имя, например Circle, там, где Rust обычно создаёт новую переменную. Но Circle в этой области видимости уже значит что-то другое: кортежный вариант, кортежную структуру или static. Rust отказывается тихо прятать это за новой переменной, потому что ты почти никогда такого не хочешь. Классический случай — ветка match Circle => после use Shape::*;, а исправление обычно занимает два символа: Circle(..). (Эта страница входит в раздел Ошибки компилятора Rust с объяснениями.)

error[E0530]: match bindings cannot shadow tuple variants
--> src/main.rs:10:9
|
6 | use Shape::*;
| -------- the tuple variant `Circle` is imported here
...
10 | Circle => "circle", // ❌ `Circle` holds a value
| ^^^^^^
| |
| cannot be named the same as a tuple variant
| help: try specify the pattern arguments: `Circle(..)`

По-русски: «привязки в match не могут затенять кортежные варианты». rustc показывает, откуда пришло имя Circle, и предлагает указать аргументы образца: Circle(..).

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

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle => "circle", // ❌ `Circle` holds a value
Square(_) => "square",
}
}
fn main() {
println!("{}", name(&Circle(1.0)));
}

^^^ указывает на Circle в строке 10, а --- в строке 6 показывает, откуда это имя: use Shape::*; принёс вариант Shape::Circle в область видимости.

В образце простое имя вроде x или other создаёт новую переменную, которая совпадает с чем угодно. Поэтому Circle => может значить две вещи:

  • «совпади с вариантом Circle» — но Circle хранит f64, так что правильному образцу нужны круглые скобки: Circle(_) или Circle(..);
  • «совпади с чем угодно и назови это Circle» — новая переменная, которая спрятала бы вариант.

Rust гадать не будет. Заголовок говорит, с каким именем ты столкнулся, а первое слово — где:

  • match bindings cannot shadow ... — в ветке match;
  • let bindings cannot shadow ... — в let или if let;
  • function parameters cannot shadow ... — в списке параметров функции;

а заканчивается он на tuple variants (кортежные варианты), tuple structs (кортежные структуры) или statics (статические переменные).

Это как назвать собаку «Доктор». Каждый раз, когда в приёмной кто-то крикнет «Доктор!», никто не поймёт, кого зовут.

Без этого правила Circle => была бы новой переменной с именем Circle. Она совпадала бы с любым значением, и все ветки после неё стали бы мёртвым кодом. Программа скомпилировалась бы, а потом печатала бы «circle» и для квадратов. Это неприятный баг, который прячется за кодом, выглядящим правильно.

Поэтому Rust считает ошибкой любой случай, когда новая переменная заняла бы имя кортежного варианта, кортежной структуры или static. Либо ты говоришь, что имеешь в виду, с помощью скобок, либо выбираешь другое имя. Единичные варианты вроде None и константы (const) — другое дело: они сами по себе правильные образцы, поэтому Rust читает их как «совпади с этим значением». Подробнее — в уроках Сопоставление с образцом и Перечисления.

Исправление 1: Добавь (..) или (_), чтобы сопоставить вариант

Заголовок раздела «Исправление 1: Добавь (..) или (_), чтобы сопоставить вариант»

Выбирай этот вариант, когда в сообщении написано tuple variants или tuple structs — это самый частый случай. Ты имел в виду вариант, так что дай ему скобки, как предлагает help rustc. Полный путь, Shape::Circle(_), ещё понятнее:

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle(..) => "круг", // ✅ вариант с любым значением внутри
Square(_) => "квадрат",
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ полный путь, и значение используется
Shape::Square(side) => side * side,
}
}
fn main() {
let shapes = [Circle(1.0), Square(2.0)];
for shape in &shapes {
println!("{}: {:.2}", name(shape), area(shape));
}
}

Вывод:

круг: 3.14
квадрат: 4.00
▶ Попробуй сам

.. значит «что бы там ни было внутри», и это продолжит работать, если у варианта позже появятся новые значения. Подробнее — в уроке Сопоставление с образцом.

Выбирай этот вариант, когда тебе действительно нужна новая переменная, а её имя просто совпало с типом. Так часто бывает с let и параметрами функций, когда переменную называют по имени её типа:

error[E0530]: let bindings cannot shadow tuple structs
--> src/main.rs:4:9
|
1 | struct Meters(f64);
| ------------------- the tuple struct `Meters` is defined here
...
4 | let Meters = 5.0; // ❌ `Meters` is a tuple struct
| ^^^^^^ cannot be named the same as a tuple struct

rustc пишет, что привязки let не могут затенять кортежные структуры. Программа, которая к этому приводит (комментарий значит «Meters — кортежная структура»):

struct Meters(f64);
fn main() {
let Meters = 5.0; // ❌ `Meters` is a tuple struct
println!("{}", Meters);
}

Стиль именования Rust решает это за тебя: типы и варианты пишутся в CamelCase, а переменные — в snake_case. Возьми имя с маленькой буквы, и конфликта нет:

struct Meters(f64);
fn total(meters: &[Meters]) -> f64 {
meters.iter().map(|m| m.0).sum()
}
fn main() {
let meters = 5.0; // ✅ имя переменной с маленькой буквы
println!("{} м", meters);
let Meters(height) = Meters(1.8); // ✅ или разбери кортежную структуру
println!("рост: {} м", height);
println!("всего: {} м", total(&[Meters(2.0), Meters(3.5)]));
}

Вывод:

5 м
рост: 1.8 м
всего: 5.5 м
▶ Попробуй сам

С параметром то же самое: fn show(Point: i32) даёт function parameters cannot shadow tuple structs, а fn show(point: i32) это исправляет. Подробнее — в разделе Правила именования.

Исправление 3: Используй const (или охранное условие) вместо static

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

Выбирай этот вариант, когда в сообщении написано statics. Скорее всего, ты хотел сравнить с фиксированным значением. static нельзя использовать как образец, а const можно:

error[E0530]: match bindings cannot shadow statics
--> src/main.rs:5:9
|
1 | static LIMIT: u32 = 100;
| ------------------------ the static `LIMIT` is defined here
...
5 | LIMIT => "full", // ❌ a static can't be a pattern
| ^^^^^ cannot be named the same as a static

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

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

Замени static на const. Если он должен остаться static (например, потому что другой код берёт его адрес), привяжи значение к имени и сравни в охранном условии (match guard):

const LIMIT: u32 = 100; // ✅ const работает как образец
static MAX_USERS: u32 = 500; // static остаётся static
fn status(users: u32) -> &'static str {
match users {
LIMIT => "мест нет",
_ => "открыто",
}
}
fn premium_status(users: u32) -> &'static str {
match users {
n if n >= MAX_USERS => "мест нет", // ✅ static сравниваем в охранном условии
_ => "открыто",
}
}
fn main() {
println!("{}", status(100));
println!("{}", status(42));
println!("{}", premium_status(500));
}

Вывод:

мест нет
открыто
мест нет
▶ Попробуй сам

Для простого числа static вообще редко нужен. Обычный выбор — const; см. раздел Константы.

Ok => или Some => без скобок. Ok, Err и Some — кортежные варианты из прелюдии, поэтому match result { Ok => ... } даёт E0530 с подсказкой try specify the pattern arguments: `Ok(..)` . Исправление: Ok(_) => или Ok(value) =>.

Внутри if let. if let Some(Some) = x пытается назвать внутреннее значение Some и даёт let bindings cannot shadow tuple variants. Исправление: имя с маленькой буквы, if let Some(inner) = x.

С полным путём это уже E0532. Shape::Circle => не может быть новой переменной (в имени переменной не бывает ::), поэтому rustc сообщает E0532, expected unit struct, unit variant or constant, found tuple variant. Исправление то же: добавь (_) или (..).

let с именем единичной структуры — это E0308. Если есть struct Guest;, строка let Guest = "Ana"; вообще не создаёт переменную: rustc читает Guest как единичную структуру и сообщает E0308 (несовпадение типов) со словами `Guest` is interpreted as a unit struct, not a new binding («Guest понимается как единичная структура, а не новая привязка»). Исправление: переименуй переменную, let guest = "Ana";.

Проверь себя

1. После use Shape::*;, где Circle(f64) — вариант, какая ветка match скомпилируется?

2. rustc пишет «let bindings cannot shadow tuple structs» для let Meters = 5.0;. Какое исправление самое простое?

3. static LIMIT: u32 = 100; нельзя использовать как образец в match. А что можно?

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