Logo

Rust 기초 – 열거형(Enum) 사용법

Rust에서 구조체가 데이터 구조를 표현하는 방법라면, 열거형은 선택지를 추상화하는데 특화된 자료형입니다.

이 글에서는 Rust에서 열거형이 무엇이고 어떻게 사용하는지 예제와 함께 살펴보겠습니다.

열거형이란?

열거형(Enum)은 여러 가지 가능한 값(variant) 중 하나만 가질 수 있는 사용자 정의(custom) 자료형(type)입니다. enum 키워드로 열거형의 이름을 붙이고, 중괄호 안에 모든 배리언트 이름을 나열하면 됩니다.

예를 들어, 웹에서 발생할 수 있는 4가지 이벤트로 이루어진 열거형으로 다음과 같이 정의할 수 있습니다.

enum Event {
    Click,
    Focus,
    Input,
    Keyboard,
}

fn main() {
    let click = Event::Click;
    let focus = Event::Focus;
    let input = Event::Input;
    let key = Event::Keyboard;
}

열거형의 배리언트는 열거형명::배리언트명 형식으로 접근할 수 있습니다.

데이터 할당

열거형의 각 배리언트는 단순한 이름이 아닌 구조체나 튜플의 형태로 정의할 수도 있는데요. 이렇게 하면 배리언트에 부가적인 데이터를 저장할 수 있게 되지요.

enum Event {
    Click { x: i32, y: i32 },
    Focus,
    Input(String),
    Keyboard(char),
}

fn main() {
    let click = Event::Click { x: 30, y: 70 };
    let focus = Event::Focus;
    let input = Event::Input(String::from("Hello"));
    let key = Event::Keyboard('A');
}

패턴 매칭

Rust에서 열거형은 패턴 매칭(Pattern Matching)을 통해서 그 진가를 발휘합니다. match 문을 통해서 각 베리언트에 해당하는 코드를 효과적으로 분기 처리할 수 있습니다.

fn handle(event: &Event) {
    match event {
        Event::Click { x, y } => println!("좌표 ({x}, {y})를 클릭했습니다."),
        Event::Focus => println!("포커스가 이동했습니다."),
        Event::Input(text) => println!("{text}를 입력하였습니다."),
        Event::Keyboard(ch) => println!("키보드 키 {ch}를 눌렀습니다."),
    }
}

배리언트에 저장되어 있는 부가적인 데이터는 배리언트는 구조 분해 할당(Destructuring)을 통해서 읽어올 수 있습니다.

fn main() {
    let click = Event::Click { x: 30, y: 70 };
    let focus = Event::Focus;
    let input = Event::Input(String::from("Hello"));
    let key = Event::Keyboard('A');

    handle(&click);
    handle(&focus);
    handle(&input);
    handle(&key);
}
좌표 (30, 70)를 클릭했습니다.
포커스가 이동했습니다.
Hello를 입력하였습니다.
키보드 키 A를 눌렀습니다.

메서드 추가

열거형을 이루고 있는 배리언트를 상대로 빈번하게 수행해야 하는 작업은 열거형에 메서드로 추가할 수 있습니다.

impl 키워드로 대상 열거체의 이름을 명시하고, 중괄호 안에 메서드를 일반 함수 정의하듯이 나열해주면 됩니다. 메서드 안에서 인스턴스의 필드에 접근할 수 있도록, 첫 번째 매개변수인 self를 통해서 인스턴스 자신이 넘어오게 되어있습니다.

예를 들어, 위에서 작성한 handle() 함수를 Event 열거형에 메서드로 추가해보겠습니다.

impl Event {
    fn handle(&self) {
        match self {
            Event::Click { x, y } => println!("좌표 ({x}, {y})를 클릭했습니다."),
            Event::Focus => println!("포커스가 이동했습니다."),
            Event::Input(text) => println!("{text}를 입력하였습니다."),
            Event::Keyboard(ch) => println!("키보드 키 {ch}를 눌렀습니다."),
        }
    }
}

그러면 이렇게 열거형의 베리언트를 상대로 메서드를 호출할 수 있습니다.

fn main() {
    let click = Event::Click { x: 30, y: 70 };
    let focus = Event::Focus;
    let input = Event::Input(String::from("Hello"));
    let key = Event::Keyboard('A');

    click.handle();
    focus.handle();
    input.handle();
    key.handle();
}

전체 코드

본 포스팅에서 작성한 실습 코드는 Rust Playgrond 확인하시고 직접 실행해보실 수 있습니다.

마치며

Rust의 열거형은 선택지가 정해진 자료형을 정의하고 부가적인 데이터까지 저장할 수 있는 풍부한 추상화 수단입니다. 특히 Rust의 패턴 매칭과 함께 활용하먄 매우 강력한 표현력을 갖추게 되죠.