상세 컨텐츠

본문 제목

18. Rust 열거 Enum

Rust를 처음부터 배우세요

by 러스트코리아 2024. 11. 20. 02:11

본문

반응형

18.1 열거

백만 분의 1 문제, 수많은 옵션 중에서 하나를 선택하는 문제처럼 Rust는 이를 표현하기 위해 새로운 데이터 유형을 제공합니다.

이 새로운 데이터 유형은 열거형 (영어 enum) 입니다 .

즉, 열거형은 변경 가능한 여러 목록 중 하나를 선택하는 데 사용됩니다.

18.2 열거형 정의

Rust 언어는 열거형을 정의하기 위한 enum 키워드를 제공합니다.

열거형을 정의하는 구문 형식은 다음과 같습니다.

  1. enum enum_name {
  2. variant1,
  3. variant2,
  4. variant3
  5. }

예를 들어 위의 바나나 및 파인애플 옵션에 대해 과일 열거형을 정의할 수 있습니다.

  1. enum Fruits {
  2.   바나나,  
  3.   파인애플,
  4.   포도, 
  5.   사과
  6. }

18.3 열거형 사용하기

열거형이 정의된 후에는 열거형을 사용하는 방법이 매우 간단합니다. 즉, 열거형 이름::열거형 값입니다. 구문 형식은 다음과 같습니다

  1. enum_name::variant

예를 들어, 위 열거형에서 바나나를 선택하면 할당 구문은 다음과 같습니다.

  1. let selected = Fruits::바나나;

유형을 명시적으로 지정해야 하는 경우 다음을 수행할 수 있습니다.

  1. let selected: Fruits = Fruits::바나나;

18.3.1 예

다음 예제에서는 열거형의 기본적인 사용 방법과 사례를 보여줍니다.

먼저 바나나, 배, 만다린, 가지라는 4개의 열거형 값을 갖는 Fruits 열거형을 정의했습니다.

println!()은 열거형을 인쇄하는 데 사용됩니다.

참고: 나중에 열거형 앞에 #[derive(Debug)]를 소개하겠습니다.

  1. #[derive(Debug)]
  2. enum Fruits {
  3.   바나나,
  4.   파인애플,
  5.   포도, 
  6.   사과
  7. }
  8.  
  9. fn main() {
  10. let selected = Fruits::바나나;
  11. println!("{:?}",selected);
  12. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. 바나나

18.4 #[derive(Debug)] 주석

Enum Fruits 앞에 #[derive(Debug)]가 있는 것을 보셨을 것입니다.

이 #[derive(Debug)] 문의 기능은 무엇입니까?

먼저 설명하지 않겠습니다. #[derive(Debug)] 를 제거하고 살펴보겠습니다.

  1. enum Fruits {
  2.   바나나,
  3.   파인애플, 
  4.   포도, 
  5.   사과
  6. }
  7.  
  8. fn main() {
  9. let selected = Fruits::바나나;
  10. println!("{:?}",selected);
  11. }

위의 Rust 코드를 컴파일하거나 오류를 보고하면 다음과 같습니다.

  1. error[E0277]: `Fruits` doesn't implement `std::fmt::Debug`
  2. --> src/main.rs:11:20
  3. |
  4. 11 | println!("{:?}",selected);
  5. | ^^^^^^^^ `Fruits` cannot be formatted using `{:?}`
  6. |
  7. = help: the trait `std::fmt::Debug` is not implemented for `Fruits`
  8. = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug`
  9. = note: required by `std::fmt::Debug::fmt`

이 오류의 의미는 우리의 Enum Fruits 열거가 std::fmt::Debug 특성을 구현하지 않는다는 것입니다.

나중에 특성을 소개하겠습니다. 여기서는 특성을 인터페이스로 처리하면 됩니다.

컴파일을 통과하려면 std::fmt::Debug 특성을 이미 구현한 것에서 열거형을 파생시키거나 파생시켜야 합니다. 이에 대한 가장 일반적인 것은 디버그입니다.

따라서 #[derive(Debug)] 주석의 기능은 Debug에서 파생된 Fruit을 만드는 것입니다.

하지만 실제로는 #[derive(Debug)] 주석을 추가하더라도 여전히 경고가 표시됩니다.

  1. #[derive(Debug)]
  2. enum Fruits {
  3.   바나나,
  4.   파인애플, 
  5.   포도,
  6.   사과
  7. }
  8.  
  9. fn main() {
  10. let selected = Fruits::바나나;
  11. println!("{:?}",selected);
  12. }

컴파일 결과는 다음과 같습니다

  1. warning: variants `파인애플`, `포도`, and `사과` are never constructed
     --> src/main.rs:4:3
      |
    2 | enum Fruits {
      |      ------ variants in this enum
    3 |   바나나,
    4 |   파인애플,
      |   ^^^^^^^^
    5 |   포도, 
      |   ^^^^
    6 |   사과
      |   ^^^^
      |
      = note: `Fruits` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
      = note: `#[warn(dead_code)]` on by default

이는 아마도 우리가 사용하지 않은 열거형이 아직 구성되지 않았음을 의미할 것입니다.

  1. variant is never constructed: 정확히 무엇을 의미합니까?

18.5 구조체형 struct와 열거형 enum

 지금까지 우리는 맞춤화할 수 있는 두 가지를 배웠습니다.

  • 하나는 구조 유형 struct 입니다.
  • 다른 하나는 열거형 enum입니다.

그들 사이의 관계와 연결은 무엇입니까?

약간의 관계가 있다면 열거형 enum을 구조체의 멤버변수의 데이터형으로 사용할 수 있다는 점이다.

18.5.1 예

다음 코드에서는 성별을 나타내는 열거형 GenderCategory를 정의합니다. 열거형 값은 남성과 여성을 각각 나타냅니다.

제3의 성별이 있나요? 여기서는 무시하세요.

동시에 우리는 사람을 설명하기 위해 Person 구조를 정의했습니다. 이 Person 구조는 GenderCategory 열거형을 멤버 변수 성별의 데이터 유형으로 사용합니다.

따라서 Person 구조의 일반 멤버 변수는 남성과 여성이라는 두 가지 값만 가질 수 있습니다.

  1. // 오류를 저장하려면 #[derive(Debug)]를 추가하세요.
  2. #[derive(Debug)]
  3. enum GenderCategory {
  4. Male,Female
  5. }
  6.  
  7. // 오류를 저장하려면 #[derive(Debug)]를 추가하세요.
  8. #[derive(Debug)]
  9. struct Person {
  10. name:String,
  11. gender:GenderCategory
  12. }
  13.  
  14. fn main() {
  15. let p1 = Person {
  16. name:String::from("러스트 튜토리얼"),
  17. gender:GenderCategory::Female
  18. };
  19. let p2 = Person {
  20. name:String::from("Admin"),
  21. gender:GenderCategory::Male
  22. };
  23. println!("{:?}",p1);
  24. println!("{:?}",p2);
  25. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. Person { name: "러스트 튜토리얼", gender: Female }
  2. Person { name: "Admin", gender: Male }

18.6 옵션 열거

Rust 언어 코어와 표준 라이브러리에는 많은 내장 열거형이 있으며, 그중 우리가 자주 다루는 열거형이 하나 있는데 바로 Option 열거형입니다.

Option 열거형은 선택적 옵션을 나타냅니다. None과 Some(T)의 두 가지 열거 값을 갖습니다.

  • 없음은 선택 사항이 없음을 의미합니다.
  • Some(T)은 없어도 되는 것을 의미하므로 값이 있어야 한다는 것, 즉 데이터형이 있어야 한다는 것입니다.

18.6.1 Option 열거형의 정의코드는 다음과 같다

  1. enum Option<T> {
  2. Some(T), // 값을 반환하는 데 사용
  3. None // Rust는 null을 지원하지 않지만 null을 반환하는 데 사용됩니다.
  4. the null keyword
  5. }

Rust 언어는 null 키워드를 지원하지 않으며 대신 None을 사용하여 없음을 의미합니다.

Option 열거형은 반환과 값을 나타낼 수 있거나 반환을 나타내지만 값이 없는 데 사용될 수 있기 때문에 함수에서 반환 값으로 자주 사용됩니다.

함수에 반환 값이 있으면 Some(data)을 반환할 수 있습니다. 함수에 반환 값이 없으면 None을 반환할 수 있습니다.

그래도 이해가 안 되시면 예시를 보시면 됩니다.

18.6.2 예

다음 예에서는 Option 열거형을 반환 값 유형으로 사용하여 is_even() 함수를 정의합니다.

is_even() 함수에 전달된 매개변수가 짝수이면 전달된 매개변수가 반환되고, 홀수이면 None이 반환됩니다.

  1. fn main() {
  2. let result = is_even(3);
  3. println!("{:?}",result);
  4. println!("{:?}",is_even(30));
  5. }
  6. fn is_even(no:i32)->Option<bool> {
  7. if no %2 == 0 {
  8. Some(true)
  9. } else {
  10. None
  11. }
  12. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. None
  2. Some(true)

18.7 match 문과 열거형

열거의 또 다른 중요한 작업은 열거 값을 판단하는 것입니다. 열거형 값을 결정하는 데 == 비교 연산자는 효과가 없습니다.

정확하게 말하면 오류가 보고됩니다.

  1. #[derive(Debug)]
  2. enum Fruits {
  3.   바나나, 
  4.   파인애플,
  5.   포도, 
  6.   사과
  7. }
  8.  
  9. fn main() {
  10. let selected = Fruits::바나나;
  11. if selected == Fruits::바나나 {
  12. println!("바나나를 선택했어요");
  13. } else {
  14. println!("다른 걸 선택했어요");
  15. }
  16. println!("{:?}",selected);
  17. }

컴파일 오류

  1. --> src/main.rs:11:17
  2. |
  3. 11 | if selected == Fruits::Banana {
  4. | -------- ^^ -------------- Fruits
  5. | |
  6. | Fruits
  7. |
  8. = note: an implementation of `std::cmp::PartialEq` might be missing for `Fruits`

열거형 변수의 값을 결정하기 위해 사용할 수 있는 유일한 연산자는 match 문입니다.

match 문에 대해서는 이미 배웠으므로 여기서는 소개하지 않겠습니다. 바로 예제로 가서 match 문을 사용하여 열거형 값을 결정하는 방법을 살펴보겠습니다.

18.7.1 예

다음 코드에서는 CarType 열거형과 CarType 열거형 변수를 받아들이고 match 문을 사용하여 열거형 변수의 값을 결정하는 함수 print_size()를 정의합니다.

  1. enum CarType {
  2. Hatch,
  3. Sedan,
  4. SUV
  5. }
  6. fn print_size(car:CarType) {
  7. match car {
  8. CarType::Hatch => {
  9. println!("Small sized car");
  10. },
  11. CarType::Sedan => {
  12. println!("medium sized car");
  13. },
  14. CarType::SUV =>{
  15. println!("Large sized Sports Utility car");
  16. }
  17. }
  18. }
  19. fn main(){
  20. print_size(CarType::SUV);
  21. print_size(CarType::Hatch);
  22. print_size(CarType::Sedan);
  23. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. Large sized Sports Utility car
  2. Small sized car
  3. medium sized car

18.8 match 문과 Option 유형

match 문은 열거형 변수의 값을 비교하고 판단하는 데 사용할 수 있으므로 위에서 언급한 Option 열거형에도 match 문을 사용합니다.

실제로 match 문과 Option 유형의 조합은 Option 열거형의 강력한 기능을 반영할 수 있습니다.

  1. fn main() {
  2. match is_even(5) {
  3. Some(data) => {
  4. if data==true {
  5. println!("Even no");
  6. }
  7. },
  8. None => {
  9. println!("not even");
  10. }
  11. }
  12. }
  13. fn is_even(no:i32)->Option<bool> {
  14. if no%2 == 0 {
  15. Some(true)
  16. } else {
  17. None
  18. }
  19. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. not even

18.9 데이터 유형이 있는 일치 문 및 열거형

Rust의 Enum 값은 고유한 데이터 유형을 가질 수 있습니다. 데이터 유형이 포함된 열거형 값 구문은 일치 문과 열거형을 전례 없는 수준으로 완전히 밀어냅니다.

더욱 강력한 점은 각 열거형 값이 서로 다른 데이터 유형을 가질 수 있다는 것입니다.

데이터 유형이 있는 열거형 값의 구문 형식은 다음과 같이 매우 간단합니다.

  1. enum enum_name {
  2. variant1(data_type1),
  3. variant2(data_type2),
  4. variant3(data_type1)
  5. }

예를 들어 다음 열거형은

  1. enum GenderCategory {
  2. Name(String),
  3. Usr_ID(i32)
  4. }

열거형 GenderCategory에는 String과 i32라는 서로 다른 데이터 유형을 갖는 두 개의 열거형 값인 Name과 User_ID가 있습니다.

18.9.1 예

다음 예에서는 데이터 유형으로 GenderCategory 열거형을 정의합니다. 그런 다음 데이터 유형으로 열거 값을 초기화하고 일치 문의 판단을 보여줍니다.

  1. // 오류보고
  2. #[derive(Debug)]
  3. enum GenderCategory {
  4. Name(String),Usr_ID(i32)
  5. }
  6. fn main() {
  7. let p1 = GenderCategory::Name(String::from("Mohtashim"));
  8. let p2 = GenderCategory::Usr_ID(100);
  9. println!("{:?}",p1);
  10. println!("{:?}",p2);
  11.  
  12. match p1 {
  13. GenderCategory::Name(val)=> {
  14. println!("{}",val);
  15. }
  16. GenderCategory::Usr_ID(val)=> {
  17. println!("{}",val);
  18. }
  19. }
  20. }

위의 Rust 코드를 컴파일하고 실행하면 출력 결과는 다음과 같습니다.

  1. Name("Mohtashim")
  2. Usr_ID(100)
  3. Mohtashim
현재 콘텐츠 저작권은 chapin666 또는 그 계열사에 있습니다.
반응형

'Rust를 처음부터 배우세요' 카테고리의 다른 글

20. Rust 컬렉션  (0) 2024.12.14
19. Rust 모듈  (0) 2024.11.27
17. Rust 구조 (Struct)  (0) 2024.11.15
16. Rust 슬라이스  (0) 2024.11.15
15. Rust는 차용(빌려줌) - Borrowing  (0) 2024.11.15

관련글 더보기