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`에는 필드가 있어요 | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant |help: the struct variant's field is being ignored |8 | Shape::Circle { radius: _ } => "circle", // ❌ `Circle`에는 필드가 있어요 | +++++++++++++“expected unit struct, unit variant or constant, found struct variant Shape::Circle“은 “유닛 구조체, 유닛 배리언트, 상수 중 하나가 와야 하는데 구조체 배리언트 Shape::Circle이 왔다”는 뜻이에요. help:는 “구조체 배리언트의 필드를 무시하는 중이다”라며 필드를 무시하는 패턴을 제안해요.
이 에러를 내는 프로그램은 다음과 같아요.
enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "circle", // ❌ `Circle`에는 필드가 있어요 Shape::Square { .. } => "square", }}
fn main() { println!("{}", name(&Shape::Square { side: 2.0 }));}무슨 뜻인가요
섹션 제목: “무슨 뜻인가요”^^^는 Shape::Circle을 가리키고, 첫 줄은 그 자리에 무엇이 올 수 있었는지 알려 줘요. 이름만 있는 패턴은 다음 셋 중 하나여야 해요.
- 유닛 구조체(unit struct):
struct Empty;같은 것 - 유닛 배리언트(unit variant):
Shape::Empty나None처럼 데이터가 없는 배리언트 - 상수(constant):
const MAX: u32 = 100;같은 것
Shape::Circle은 그 어느 것도 아니에요. radius를 담고 있는 구조체 배리언트(struct variant)예요. 그냥 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`에는 이름 있는 필드가 있어요 | ^^^^^^^^^^^^^ not a value |help: you might have meant to create a new value of the struct |8 - let shape = Shape::Circle(2.0); // ❌ `Circle`에는 이름 있는 필드가 있어요8 + let shape = Shape::Circle { radius: /* value */ }; // ❌ `Circle`에는 이름 있는 필드가 있어요 |라벨 “not a value”는 “값이 아니다”라는 뜻이고, help:는 “구조체의 새 값을 만들려던 것 같다”며 중괄호를 쓴 줄을 보여 줘요.
이 에러를 내는 프로그램이에요.
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn main() { let shape = Shape::Circle(2.0); // ❌ `Circle`에는 이름 있는 필드가 있어요 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", // ❌ 함수는 패턴이 될 수 없어요 | ^^^^^^^^^^^^^^^^^ 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", // ❌ 함수는 패턴이 될 수 없어요 _ => "open", }}
fn main() { println!("{}", status(100));}값이 절대 바뀌지 않는다면 const로 만드세요. 상수는 패턴이 될 수 있어요. 계산이 필요한 값이라면 함수는 그대로 두고, if를 쓴 매치 가드(match guard)에서 비교하세요.
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));}실행 결과:
비어 있음꽉 참자리 있음더는 방을 만들 수 없어요방을 하나 더 만들 수 있어요매치 가드는 매치 가드: if 덧붙이기에서 설명해요.
자주 보게 되는 곳
섹션 제목: “자주 보게 되는 곳”유닛 배리언트에 필드가 생긴 뒤. 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 { .. } =>라고 쓰거나, bool이 바로 필요하면 matches!(shape, Shape::Circle { .. })라고 쓰세요.
튜플 배리언트 버전. Circle(f64) 같은 튜플 배리언트에 그냥 Shape::Circle => 갈래를 쓰면 다른 코드인 E0532가 나요. 첫 줄은 같은 모양으로 “expected unit struct, unit variant or constant, found tuple variant Shape::Circle“이에요. 해결은 Shape::Circle(_)이나 Shape::Circle(..)이에요. 반대로 Circle { radius: f64 }에 대해 Shape::Circle(r) =>처럼 구조체 배리언트를 패턴에서 괄호로 쓰면 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 (영어): 이 에러의 공식 설명이에요.
- 패턴 문법 — The Rust Programming Language 한국어판: 열거형 분해하기,
..로 값 무시하기, 매치 가드를 다뤄요. - Destructuring enums — Rust by Example (영어): 유닛, 튜플, 구조체 배리언트를 나란히 매칭하는 예제예요.
- E0532 — Rust error codes index (영어): 같은 실수의 튜플 배리언트 버전에 대한 공식 페이지예요.
- Patterns — The Rust Reference (영어): 패턴으로 쓸 수 있는 경로, 구조체 패턴과 튜플 구조체 패턴의 규칙이에요.