콘텐츠로 이동

Rust 에러 E0530: match bindings cannot shadow tuple variants (튜플 배리언트 가리기)

E0530은 패턴에 쓴 이름이 이미 다른 데 쓰이고 있다는 뜻이에요. 보통 Rust가 새 변수를 만드는 자리에 Circle 같은 이름을 그냥 썼는데, 이 스코프에서 Circle은 이미 다른 것을 뜻해요. 튜플 배리언트, 튜플 구조체, 또는 static이요. Rust는 그 이름을 새 변수 뒤에 슬쩍 가려 버리지 않아요. 그게 내가 원한 일일 리가 거의 없으니까요. 대표적인 경우는 use Shape::*; 다음에 match 갈래를 Circle =>라고 쓴 거예요. 해결은 보통 두 글자면 돼요. 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`은 값을 담고 있어요
| ^^^^^^
| |
| cannot be named the same as a tuple variant
| help: try specify the pattern arguments: `Circle(..)`

이 에러를 내는 프로그램은 다음과 같아요.

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle => "원", // ❌ `Circle`은 값을 담고 있어요
Square(_) => "정사각형",
}
}
fn main() {
println!("{}", name(&Circle(1.0)));
}

^^^는 10번째 줄의 Circle을 가리키고, 6번째 줄의 ---는 그 이름이 어디서 왔는지 보여 줘요. use Shape::*;가 배리언트 Shape::Circle을 스코프로 가져왔어요. 라벨은 “튜플 배리언트와 같은 이름을 붙일 수 없다”는 뜻이고, help:는 “패턴 인자를 적어 보라: 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(static) 중 하나예요.

강아지 이름을 “선생님”이라고 지은 것과 비슷해요. 병원 대기실에서 누가 “선생님!” 하고 부를 때마다, 누구를 부르는 건지 아무도 몰라요.

이 규칙이 없다면 Circle =>는 Circle이라는 새 변수가 될 거예요. 그 변수는 모든 값과 매칭되고, 그 뒤의 갈래는 전부 절대 실행되지 않는 코드가 돼요. 프로그램은 컴파일되지만, 정사각형에도 “원”을 출력해요. 겉보기엔 맞는 코드 뒤에 숨은 고약한 버그예요.

그래서 Rust는 새 변수가 튜플 배리언트, 튜플 구조체, static의 이름을 가져가려고 하면 언제나 에러로 처리해요. 괄호를 붙여서 뜻을 분명히 하거나, 다른 이름을 고르면 돼요. None 같은 유닛 배리언트와 상수(const)는 달라요. 이것들은 그 자체로 올바른 패턴이라서, Rust는 “이 값과 매칭하라”로 읽어요. 패턴 매칭과 열거형을 참고하세요.

방법 1: (..)나 (_)를 붙여서 배리언트와 매칭하기

섹션 제목: “방법 1: (..)나 (_)를 붙여서 배리언트와 매칭하기”

메시지에 tuple variants나 tuple structs가 있을 때 이 방법을 고르세요. 가장 흔한 경우예요. 원래 배리언트를 뜻했으니, rustc의 help대로 괄호를 붙여 주세요. 전체 경로 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`는 튜플 구조체예요
| ^^^^^^ cannot be named the same as a tuple struct

라벨은 “튜플 구조체와 같은 이름을 붙일 수 없다”는 뜻이에요. 문제가 되는 프로그램은 이래요.

struct Meters(f64);
fn main() {
let Meters = 5.0; // ❌ `Meters`는 튜플 구조체예요
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!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ 또는 튜플 구조체를 구조 분해하기
println!("키: {} m", height);
println!("합계: {} m", total(&[Meters(2.0), Meters(3.5)]));
}

실행 결과:

5 m
키: 1.8 m
합계: 5.5 m
▶ 직접 실행해 보기

매개변수도 마찬가지예요. fn show(Point: i32)는 function parameters cannot shadow tuple structs(함수 매개변수는 튜플 구조체를 가릴 수 없다)를 내고, fn show(point: i32)로 고치면 돼요. 이름 짓는 규칙을 참고하세요.

방법 3: static 대신 const(또는 매치 가드) 쓰기

섹션 제목: “방법 3: static 대신 const(또는 매치 가드) 쓰기”

메시지에 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 => "가득 참", // ❌ static은 패턴이 될 수 없어요
| ^^^^^ cannot be named the same as a static

라벨은 “static과 같은 이름을 붙일 수 없다”는 뜻이에요. 문제가 되는 프로그램은 이래요.

static LIMIT: u32 = 100;
fn status(users: u32) -> &'static str {
match users {
LIMIT => "가득 참", // ❌ static은 패턴이 될 수 없어요
_ => "자리 있음",
}
}
fn main() {
println!("{}", status(100));
}

static을 const로 바꾸세요. 꼭 static으로 남겨야 한다면(예를 들어 다른 코드가 그 주소를 가져다 쓴다면), 값을 이름에 묶고 매치 가드에서 비교하세요.

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 => ... }는 try specify the pattern arguments: `Ok(..)` 라는 help와 함께 E0530을 내요. 해결: Ok(_) =>나 Ok(value) =>라고 쓰세요.

if let 안에서. if let Some(Some) = x는 안쪽 값을 Some이라고 부르려고 해서 let bindings cannot shadow tuple variants(let 바인딩은 튜플 배리언트를 가릴 수 없다)를 내요. 해결: 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를 유닛 구조체로 읽고 `Guest` is interpreted as a unit struct, not a new binding(Guest는 새 바인딩이 아니라 유닛 구조체로 해석된다)라며 E0308(타입 불일치)을 보고해요. 해결: let guest = "Ana";처럼 변수 이름을 바꾸세요.

이해도 점검

1. Circle(f64)가 배리언트이고 use Shape::*;를 썼어요. 어떤 match 갈래가 컴파일될까요?

2. let Meters = 5.0;에 rustc가 "let bindings cannot shadow tuple structs"라고 해요. 가장 간단한 해결책은 무엇일까요?

3. static LIMIT: u32 = 100;은 match 패턴으로 쓸 수 없어요. 무엇은 쓸 수 있을까요?

점수: 0 / 3