hyunsu blog

홈강좌Rust 입문·중급 47편 중 24편째

Rust 열거형 — 정해진 몇 가지 중 하나를 타입으로 만든다

목차 · 3
  1. 01enum 으로 경우를 늘어놓는다
  2. 02없는 경우를 쓰면 E0599
  3. 03실습 — 경우마다 데이터 붙이기

Rust 열거형(enum)은 신호등의 빨강·노랑·초록처럼 정해진 몇 가지 중 하나인 값을 타입으로 만든다. Light::Red 처럼 타입 이름과 :: 로 고르고, 없는 이름을 쓰면 E0599 가 난다. 경우마다 다른 데이터를 붙일 수도 있다.

01 enum 으로 경우를 늘어놓는다

rust
#[derive(Debug, PartialEq)]
enum Light {
    Red,
    Yellow,
    Green,
}

fn main() {
    let now = Light::Red;
    println!("{now:?}");

    for light in [Light::Red, Light::Yellow, Light::Green] {
        let can_go = light == Light::Green;
        println!("{light:?}: can go = {can_go}");
    }
}
text
   Compiling light v0.1.0 (~/projects/light)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
     Running `target/debug/light`
Red
Red: can go = false
Yellow: can go = false
Green: can go = true
  • enum Light { Red, Yellow, Green } 은 새 타입 Light 를 정의한다. 중괄호 안의 이름 하나하나를 경우(variant)라 한다.
  • 값은 Light::Red 처럼 타입 이름 뒤에 :: 로 고른다. Light 타입의 값은 셋 중 반드시 하나다. 넷째 값은 없다.
  • #[derive(Debug, PartialEq)] 는 22편의 derive 에 기능을 하나 더한 것이다. Debug 는 {:?} 로 찍기, PartialEq 는 == 로 비교하기다.

신호등 상태를 문자열 "red" 나 숫자 0 으로 다룰 수도 있다. 하지만 그러면 "rde" 같은 오타나 7 같은 엉뚱한 값도 들어간다. 열거형이면 그런 값은 아예 만들 수 없다.

02 없는 경우를 쓰면 E0599

rust
#[derive(Debug)]
enum Light {
    Red,
    Yellow,
    Green,
}

fn main() {
    let now = Light::Blue;
    println!("{now:?}");
}
text
error[E0599]: no variant or associated item named `Blue` found for enum `Light` in the current scope
 --> src/main.rs:9:22
  |
2 | enum Light {
  | ---------- variant or associated item `Blue` not found for this enum
...
9 |     let now = Light::Blue;
  |                      ^^^^ variant or associated item not found in `Light`
  1. 무엇 — enum Light 에 Blue 라는 경우(variant)가 없다.
  2. 어디 — 9번째 줄의 Light::Blue. 2번째 줄의 정의도 함께 짚는다. ... 는 사이의 줄을 줄였다는 표시다.
  3. 고치는 법 — help: 는 없다. 정의에 있는 Red·Yellow·Green 중 하나를 쓰거나, 정말 필요하면 정의에 Blue 를 더한다.

03 실습 — 경우마다 데이터 붙이기

경우에 값을 붙일 수도 있다. 도형을 예로 들면, 원은 반지름 하나, 사각형은 가로·세로 둘, 점은 아무것도 필요 없다.

rust
#[derive(Debug)]
enum Shape {
    Circle(f64),
    Rect(f64, f64),
    Dot,
}

fn main() {
    let shapes = [Shape::Circle(1.5), Shape::Rect(3.0, 4.0), Shape::Dot];
    for s in shapes {
        println!("{s:?}");
    }
}
text
Circle(1.5)
Rect(3.0, 4.0)
Dot

Shape::Circle(1.5) 처럼 경우 이름 뒤 괄호에 값을 넣어 만든다. 구조체(22편)로 이것을 나타내려면 반지름·가로·세로 칸을 모두 두고 안 쓰는 칸을 비워야 하는데, Rust 에는 빈 칸이 없다. 열거형은 경우마다 필요한 값만 갖는다.

실제로 돌리면 위 세 줄 앞에 경고(warning: field 0 is never read)가 30줄쯤 나온다. 붙인 값을 한 번도 꺼내 쓰지 않았다는 뜻이다. 값을 꺼내려면 "지금 어느 경우인가" 를 따져야 하는데, 그 일을 하는 것이 다음 편의 match 다. 다음 편에서 이 Shape 로 넓이를 구하면 경고도 사라진다. 그 전에 enum-basic 에 Off(꺼짐) 경우를 더해 보자. for 의 배열에도 넣어야 한다.