열거형 정의와 값

열거형(enum)은 여러 가지 상이한 상태나 종류를 하나의 타입으로 묶어서 표현하는 방법이다. Rust의 열거형은 전통적인 C 계열 언어의 열거형과 달리 단순히 명명된 상수들을 나열하는 것뿐 아니라, 각 변 variant마다 서로 다른 종류의 데이터를 담을 수도 있다. 이를 통해 열거형이 나타내고자 하는 상태나 데이터의 맥락을 더욱 풍부하게 표현할 수 있다.

열거형은 보통 여러 선택지 중에서 정확히 하나를 표현하고 싶은 상황에서 자주 사용된다. 예를 들어 물건의 상태를 열거형으로 정의하거나, 네트워크 요청 결과를 성공과 실패 상태로 구분하여 표현하고 싶을 때에 열거형이 그 역할을 잘 수행한다. 열거형을 정의할 때는 enum 키워드를 사용한다. 가장 기본적인 형태는 아래와 같다.

enum Color {
    Red,
    Green,
    Blue,
}

위 예시처럼 Color라는 열거형을 정의하고, 그 안에 Red, Green, Blue라는 서로 다른 변을 선언했다. 이제 Color라는 타입의 값은 오직 Color::Red, Color::Green, Color::Blue 중 하나가 될 수 있다. 값이 정의되었으므로 다음과 같이 변수를 선언할 수 있다.

let c1 = Color::Red;
let c2 = Color::Green;
let c3 = Color::Blue;

Rust 열거형의 강력한 특징 중 하나는 변마다 서로 다른 구조의 데이터를 담을 수 있다는 점이다. 변을 단순히 기호처럼만 사용하고 끝내지 않고, 실제로 의미 있는 데이터까지 함께 넣어 관리할 수 있다. 예를 들어, 정수나 문자열, 또는 구조체를 넣어야 할 수도 있다. 이때는 튜플 형태 또는 구조체 형태로 변을 정의할 수 있다.

튜플 형태의 열거형 변은 다음과 같이 정의한다.

enum Message {
    Quit,
    Move(i32, i32),
    Write(String),
    ChangeColor(u8, u8, u8),
}

위 예시에서 Quit 변은 아무런 데이터를 가지지 않는다. 반면에 Move 변은 i32 두 개를 내부에 저장하고, Write 변은 String을, ChangeColor 변은 RGB 정보를 각각 u8으로 세 개를 묶어 가지고 있다. 이 열거형은 서로 다른 목적의 메서지를 하나의 타입 Message로 묶어 관리할 수 있게 해준다.

구조체 형태의 열거형 변 또한 가능하다. 다음 예시는 구조체처럼 필드명을 직접 부여하여 의미를 명확히 할 수 있는 방법이다.

Circle 변은 중심좌표 (x, y)와 반지름 radius를 담고, Rectangle 변은 왼쪽 위와 오른쪽 아래 꼭짓점의 좌표 (x1, y1), (x2, y2)를 담는다. 이렇게 각 변마다 구조체 형식으로 필드를 정의하여, 열거형 내부의 변이 의미하는 정보를 더욱 명확하게 코드로 드러낼 수 있다.

열거형을 사용할 때 중요한 것은, 정의된 열거형 값에 접근하거나 분기 처리를 할 때 주로 패턴 매칭을 활용한다는 점이다. 패턴 매칭은 match 키워드를 사용하여 작성하며, 열거형의 변에 따라 다른 로직을 적용할 수 있게 해준다. 간단한 예시를 살펴보자.

위 코드는 match를 통해 Message 열거형의 변을 하나씩 확인하고, 해당 변에 맞추어 필요한 코드를 실행한다. Move 변이나 ChangeColor 변처럼 내부에 담긴 데이터를 활용해야 한다면 패턴을 사용해 변수로 받아올 수 있다.

열거형은 Option, Result 같은 표준 라이브러리 타입에도 폭넓게 활용되어 있다. Option는 값이 있거나 없음을 표현하기에 유용하고, Result<T, E>는 작업이 성공했을 때의 값 T 또는 실패했을 때의 에러 E를 담는다. 이렇듯 열거형의 장점은, 프로그램 내에서 다양한 상태와 데이터를 안전하게 묶어 표현하고, 그에 따른 처리를 패턴 매칭으로 엄격하게 분기할 수 있다는 점이다.

Rust의 열거형은 구조체나 다른 자료형과 마찬가지로 impl 블록을 사용하여 메서드를 정의할 수도 있다. 특정 변에만 적용되는 메서드는 별도로 다룰 수 없지만, 열거형 전체에 공통으로 필요한 함수라면 impl 블록 안에 작성해 제공할 수 있다. 예를 들어, 열거형 변이 무엇이냐에 따라 다른 문자열을 반환하는 메서드를 구현할 수 있다. 이를 이용하면 if/else로 여러 열거형 값을 구분하지 않아도, match를 통해 내부 로직을 명확하게 정리하고 반환값을 깔끔하게 관리할 수 있다.

열거형을 정의할 때는 단순히 상태의 나열이 아니라, 변마다 다른 종류의 정보를 담을 수 있으며, 그 상태를 안전하게 처리하기 위해서는 match 문이나 if let 같은 패턴 매칭 기법이 따라온다는 점이 핵심이다. Rust는 열거형을 완전하게 분기 처리해야 한다고 강제하기 때문에, 예측하지 못한 변이나 누락된 변을 안전하게 처리할 수 있어 코드 안정성과 명확성이 높아진다.

열거형은 상황에 따른 다양한 선택지와 데이터를 한데 모아놓고, 그 중에 오직 하나의 변만 유효한 형태로 사용해야 할 때 탁월한 선택이다. 구조체와 함께 Rust 언어의 핵심적인 데이터 모델을 구성하므로, 열거형을 적극적으로 활용해 상태와 데이터를 명료하게 표현해보도록 하자.

Last updated