콘텐츠로 이동

Rust 에러 E0559: variant has no field named X (배리언트에 없는 필드 이름)

E0559는 Enum::Variant { field: value }로 열거형 값을 만드는데, 적어 넣은 필드 중 하나가 그 배리언트에 없다는 뜻이에요. 구조체에서 같은 실수를 하면 나는 E0560의 열거형 버전이에요. 보통은 필드 이름을 줄여 썼거나 철자가 틀렸거나, 다른 배리언트의 필드를 썼거나, 괄호를 써야 하는 배리언트에 중괄호를 쓴 경우예요. 거의 언제나 단어 하나만 고치면 돼요. 이 페이지는 Rust 컴파일러 에러 해설의 일부예요.

error[E0559]: variant `Shape::Circle` has no field named `r`
--> src/main.rs:8:33
|
8 | let shape = Shape::Circle { r: 2.0 }; // ❌ 필드 이름은 `radius`예요
| ^ `Shape::Circle` does not have this field
|
= note: available fields are: `radius`

“variant Shape::Circle has no field named r“는 “Shape::Circle 배리언트에는 r이라는 이름의 필드가 없다”는 뜻이에요. 라벨 `Shape::Circle` does not have this field는 “Shape::Circle에는 이 필드가 없다”, note는 “쓸 수 있는 필드는 radius“라는 뜻이에요.

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

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn main() {
let shape = Shape::Circle { r: 2.0 }; // ❌ 필드 이름은 `radius`예요
println!("{:?}", shape);
}

첫 줄은 배리언트(Shape::Circle)와 내가 쓴 필드(r)를 알려 줘요. ^는 중괄호 안의 그 필드를 가리켜요. Rust가 정의 Circle { radius: f64 }를 살펴봤는데, r이라는 필드가 없었던 거예요.

열거형의 배리언트는 저마다 자기만의 필드 목록을 가져요. Shape::Circle에는 radius가 있고, Shape::Rectangle에는 width와 height가 있어요. 같은 열거형 안에 있어도 필드를 서로 나눠 쓰지 않아요.

화살표 아래에는 다음 힌트 중 하나가 나와요. 먼저 읽어 보세요. 보통 답이 들어 있어요.

  • note: available fields are: `radius`(쓸 수 있는 필드는 radius): 비슷한 이름이 없어요. 이 배리언트에 있는 필드 중 아직 채우지 않은 것들이 나열돼요.
  • help: a field with a similar name exists(비슷한 이름의 필드가 있다): key를 kye라고 쓴 것 같은 오타예요. rustc가 고친 줄을 보여 줘요.
  • help: `Message::Write` is a tuple variant, use the appropriate syntax(Message::Write는 튜플 배리언트이니 알맞은 문법을 쓰라): 배리언트의 필드에 이름이 없어서 { }가 아니라 ( )를 써야 해요.
  • note: all struct fields are already assigned(모든 필드에 이미 값을 넣었다): 진짜 필드는 전부 채웠고, 이 필드는 남는 거예요.

피자를 주문하면서 “도우 크게”라고 적었는데, 주문서에는 “도우 크기” 칸만 있는 것과 비슷해요. 주방에서는 무슨 뜻인지 다 알지만, 주문서에 그런 이름의 칸이 없는 거죠.

Circle { radius: f64 }처럼 이름 있는 필드를 가진 배리언트는 열거형 안의 작은 구조체처럼 동작해요. 그런 배리언트를 만들 때 Rust는 정확히 그 필드들을 넣었는지 검사해요. 빠진 것도, 남는 것도, 철자가 틀린 것도 없어야 해요. 열거형은 데이터를 담을 수 있어요를 참고하세요.

이 검사가 가장 빛나는 때는 나중에 그 열거형을 match할 때예요. Shape::Circle { radius } => ... 같은 갈래는 모든 Circle에 정말로 radius가 있을 때만 제대로 동작해요. Rust가 Shape::Circle { r: 2.0 }을 통과시킨다면 그 보장이 사라지겠죠. 컴파일할 때 오타를 잡아 주니까, 프로그램 안의 모든 Circle은 언제나 빠짐없이 완전해요.

방법 1: 배리언트의 진짜 필드 이름 쓰기

섹션 제목: “방법 1: 배리언트의 진짜 필드 이름 쓰기”

rustc가 available fields are나 a field with a similar name exists를 보여 줄 때 이 방법을 고르세요. 힌트에 나온 이름을 쓰면 돼요. 필드 이름은 대소문자를 구별하고 snake_case로 쓰니까, Radius와 radius는 서로 다른 이름이에요.

오타라면 “비슷한 이름” 힌트가 나와요.

error[E0559]: variant `Event::KeyPress` has no field named `kye`
--> src/main.rs:8:31
|
8 | let e = Event::KeyPress { kye: 'a' };
| ^^^ unknown field
|
help: a field with a similar name exists
|
8 - let e = Event::KeyPress { kye: 'a' };
8 + let e = Event::KeyPress { key: 'a' };
|

라벨 unknown field는 “알 수 없는 필드”라는 뜻이고, help는 kye를 key로 바꾼 줄을 보여 줘요.

r처럼 짧은 이름은 radius와 너무 달라서 제안이 나오지 않고, 대신 필드 목록이 나와요. 어느 쪽이든 배리언트에 정의된 필드를 쓰세요.

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
#[derive(Debug)]
enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 }, // ✅ 진짜 필드 이름이에요
Shape::Rectangle { width: 3.0, height: 4.0 },
];
for shape in &shapes {
println!("{:?}", shape);
}
let events = [Event::KeyPress { key: 'a' }, Event::Click { x: 10, y: 20 }];
println!("{:?}", events);
}

실행 결과:

Circle { radius: 2.0 }
Rectangle { width: 3.0, height: 4.0 }
[KeyPress { key: 'a' }, Click { x: 10, y: 20 }]
▶ 직접 실행해 보기

필드 초기화 축약법(field init shorthand)도 조심하세요. Shape::Circle { r }은 Shape::Circle { r: r }이라는 뜻이라서 똑같이 E0559가 나요. 변수 이름이 r이라면 필드를 풀어서 쓰세요. Shape::Circle { radius: r }처럼요. 아니면 변수 이름을 radius로 바꾸고 Shape::Circle { radius }라고 쓰면 돼요.

방법 2: 튜플 배리언트에는 괄호 쓰기

섹션 제목: “방법 2: 튜플 배리언트에는 괄호 쓰기”

rustc가 is a tuple variant, use the appropriate syntax라고 할 때 이 방법을 고르세요. Write(String) 같은 배리언트에는 필드가 있지만, 그 필드에 이름이 없어요. 그래서 중괄호 안에 어떤 이름을 써도 틀려요.

error[E0559]: variant `Message::Write` has no field named `text`
--> src/main.rs:8:30
|
4 | Write(String),
| ----- `Message::Write` defined here
...
8 | let m = Message::Write { text: String::from("hi") };
| ^^^^ field does not exist
|
help: `Message::Write` is a tuple variant, use the appropriate syntax
|
8 - let m = Message::Write { text: String::from("hi") };
8 + let m = Message::Write(/* String */);
|

라벨 `Message::Write` defined here는 “Message::Write는 여기서 정의됐다”, field does not exist는 “그런 필드는 없다”는 뜻이에요.

제안에 있는 /* String */은 자리 표시자예요. 그 자리에 내 값을 넣으세요. 튜플 배리언트는 정의된 순서대로 괄호 안에 값을 넣어서 만들어요.

#[derive(Debug)]
enum Message {
Move { x: i32, y: i32 }, // 이름 있는 필드: { }를 써요
Write(String), // 이름 없는 필드: ( )를 써요
Color(u8, u8, u8),
}
fn main() {
let messages = vec![
Message::Move { x: 1, y: 2 },
Message::Write(String::from("안녕")), // ✅ 괄호
Message::Color(255, 128, 0),
];
for m in &messages {
match m {
Message::Move { x, y } => println!("이동: ({}, {})", x, y),
Message::Write(text) => println!("쓰기: {}", text),
Message::Color(r, g, b) => println!("색: {} {} {}", r, g, b),
}
}
}

실행 결과:

이동: (1, 2)
쓰기: 안녕
색: 255 128 0
▶ 직접 실행해 보기

필드에 이름을 붙이고 싶다면 정의를 Write { text: String }으로 바꾸세요. 그러면 Message::Write { text: ... }가 동작해요. 반대로 헷갈린 경우, 즉 Shape::Circle(2.0)처럼 이름 있는 필드를 가진 배리언트에 괄호를 쓰면 다른 에러가 나요. E0533, “expected value, found struct variant”(값이 와야 하는데 구조체 배리언트가 왔다)예요.

방법 3: 맞는 배리언트 고르기, 또는 배리언트 고치기

섹션 제목: “방법 3: 맞는 배리언트 고르기, 또는 배리언트 고치기”

내가 쓴 필드가 있긴 한데 다른 배리언트에 있을 때 이 방법을 고르세요. 아래에서 radius는 Square가 아니라 Circle의 필드예요.

error[E0559]: variant `Shape::Square` has no field named `radius`
--> src/main.rs:8:29
|
8 | let s = Shape::Square { radius: 2.0 };
| ^^^^^^ `Shape::Square` does not have this field
|
= note: available fields are: `side`

“Shape::Square 배리언트에는 radius 필드가 없고, 쓸 수 있는 필드는 side“라는 뜻이에요.

원래 무엇을 만들려고 했는지 생각해 보세요. 원을 원했다면 Shape::Circle { radius: 2.0 }을 쓰세요. 정사각형을 원했다면 그 필드를 쓰세요. Shape::Square { side: 2.0 }처럼요.

note: all struct fields are already assigned가 보인다면, 배리언트의 필드는 다 채웠고 내가 쓴 필드가 남는 거예요. 그 필드를 지우거나, 코드에 정말 필요하다면 배리언트 정의에 추가하세요.

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
#[derive(Debug)]
enum Message {
Move { x: i32, y: i32, z: i32 }, // 코드에 필요해서 `z`를 추가했어요
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // 원에는 반지름이 있어요
let b = Shape::Square { side: 2.0 }; // 정사각형에는 한 변의 길이가 있어요
println!("{:?}, {:?}", a, b);
let m = Message::Move { x: 1, y: 2, z: 3 };
println!("{:?}", m);
}

실행 결과:

Circle { radius: 2.0 }, Square { side: 2.0 }
Move { x: 1, y: 2, z: 3 }
▶ 직접 실행해 보기

배리언트에 필드를 추가하면, 그 배리언트를 만드는 모든 곳에서 그 필드도 채워야 해요. rustc가 그런 곳마다 E0063, “missing field”(필드 누락)로 짚어 줄 거예요.

Self::를 쓰는 생성자 메서드. impl Shape 안에서 fn circle(r: f64) -> Shape { Self::Circle { r } }이라고 쓰면, 축약법 때문에 r에서 E0559가 나요. 해결: Self::Circle { radius: r }. 열거형도 메서드를 가질 수 있어요를 참고하세요.

필드 이름을 바꾼 뒤. 열거형에서 Circle { r }을 Circle { radius }로 바꿨더니, 예전의 Shape::Circle { r: ... }마다 available fields are: `radius`와 함께 E0559가 나요. 프로젝트 전체에서 옛 이름을 검색해서 하나씩 고치세요.

match 패턴 안에서. Shape::Circle { r } => ...처럼 패턴에 틀린 필드 이름을 쓰는 것도 같은 실수지만, rustc는 다른 코드를 써요. E0026, “variant Shape::Circle does not have a field named r”(Shape::Circle 배리언트에는 r이라는 필드가 없다)와 help: `Shape::Circle` has a field named `radius`(radius라는 필드는 있다)가 나오고, E0027 “pattern does not mention field radius”(패턴이 radius 필드를 언급하지 않는다)도 함께 나와요. 해결: Shape::Circle { radius } => ..., 또는 짧은 이름을 그대로 쓰고 싶다면 Shape::Circle { radius: r } => .... 패턴 매칭을 참고하세요.

이해도 점검

1. enum Message { Write(String) }에서 Message::Write { text: s }는 어떻게 바꿔야 할까요?

2. let r = 2.0;이 있는데 Shape::Circle { r }이라고 썼어요. 필드 이름은 radius예요. 어떻게 고칠까요?

3. Shape::Square { radius: 2.0 }에서 E0559가 났고, note에는 side만 나와요. 무슨 일일까요?

점수: 0 / 3