프로그래밍 언어/[Rust]

[Rust] enum

swc0317 2024. 12. 30. 18:07
728x90
반응형
C의 enum

 

C에서의 enum은 상수 값에 의미를 부여하는 데 주로 사용됩니다.

 

#include <stdio.h>

enum Color {
    Red = 1,
    Green = 2,
    Blue = 4
};

int main() {
    enum Color myColor = Blue;
    printf("My color is: %d\n", myColor); // 출력: My color is: 4
    return 0;
}

 

반드시 각 필드에 정수 값이 할당된다는 특징이 있습니다.

 

enum Color {
    Red,    // 0
    Green,  // 1
    Blue    // 2
};

 

만약 값을 할당하지 않아도 자동으로 순서대로 0부터 값이 할당됩니다.

 

Rust의 enum

 

 

일종의 user-defined datatype을 모아둔 set입니다.

 

enum WebEvent {
    // An `enum` variant may either be `unit-like`,
    PageLoad,
    PageUnload,
    // like tuple structs,
    KeyPress(char),
    Paste(String),
    // or c-like structures.
    Click { x: i64, y: i64 },
    Number(i32), // 단일 정수 값
}

 

보시다시피 유연하게 다양한 타입의 값을 가질 수 있습니다.

 

이를 match 문법과 연계하여 다양한 데이터 타입으로 하여금

 

각각의 타입에 맞게 작동하도록 구현할 수 있습니다.

 

fn inspect(event: WebEvent) {
    match event {
        WebEvent::PageLoad => println!("page loaded"),
        WebEvent::PageUnload => println!("page unloaded"),
        // Destructure `c` from inside the `enum` variant.
        WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
        WebEvent::Paste(s) => println!("pasted \"{}\".", s),
        // Destructure `Click` into `x` and `y`.
        WebEvent::Click { x, y } => {
            println!("clicked at x={}, y={}.", x, y);
        },
    }
}
fn main() {
    let pressed = WebEvent::KeyPress('x');
    // `to_owned()` creates an owned `String` from a string slice.
    let pasted  = WebEvent::Paste("my text".to_owned());
    let click   = WebEvent::Click { x: 20, y: 80 };
    let load    = WebEvent::PageLoad;
    let unload  = WebEvent::PageUnload;

    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);
}

 

 

type aliases

 

이러한 enum의 타입뿐만 아니라 어떤 타입형에 

 

의미를 부여하기 위해 각 타입의 이름을 바꾸기 위해 

 

C++ 에선 typedef를 사용했던 것처럼 Rust도 그러한 

 

별칭 사용을 허용합니다.

 

typedef int Kilometers;

int main() {
    Kilometers distance = 100;
    std::cout << "Distance: " << distance << " km" << std::endl;
    return 0;
}

 

위는 C++의 예시입니다.

 

아래는 Rust의 예시입니다.

 

type Kilometers = i32;

fn main() {
    let distance: Kilometers = 100;
    println!("Distance: {} km", distance);
}

 

이러한 특징을 이용해 변수형에 의미를 부여할 뿐만 아니라

 

좀 enum이 이름이 길거나 하면 여러가지 의도로 사용될 수 있고요.

 

enum VeryVerboseEnumOfThingsToDoWithNumbers {
    Add,
    Subtract,
}

// Creates a type alias
type Operations = VeryVerboseEnumOfThingsToDoWithNumbers;

fn main() {
    // We can refer to each variant via its alias, not its long and inconvenient
    // name.
    let x = Operations::Add;
}

 

 

그 예시로 Self alias입니다.

 

enum VeryVerboseEnumOfThingsToDoWithNumbers {
    Add,
    Subtract,
}

impl VeryVerboseEnumOfThingsToDoWithNumbers {
    fn run(&self, x: i32, y: i32) -> i32 {
        match self {
            Self::Add => x + y,
            Self::Subtract => x - y,
        }
    }
}

fn main() {
    let add = VeryVerboseEnumOfThingsToDoWithNumbers::Add;
    let subtract = VeryVerboseEnumOfThingsToDoWithNumbers::Subtract;

    println!("Add: {}", add.run(5, 3)); // 출력: Add: 8
    println!("Subtract: {}", subtract.run(5, 3)); // 출력: Subtract: 2
}

 

"VeryVerboseEnumOfThingsToDoWithNumbers" 라는 enum에 

 

메소드를 추가하기 위해 impl을 통해 Add 타입과, Subtract 타입에 맞는 

 

행동을 구현합니다. 이때 기존의 enum이 아니라

 

Self:: 라는 구문을 통해 VeryVerboseEnumOfThingsToDoWithNumbers라는

 

기존의 enum 값을 대체할 수 있습니다.

 

use

 

C++로 치면 using namespace std; 를 통해,

 

std::cout을 cout으로 줄여 쓸 수 있는 것처럼,

 

enum이나 다른 모듈에 정의된 기능들을 쓸 수 있는 겁니다.

 

예를 들어,

 

enum Stage {
    Beginner,
    Advanced,
}

enum Role {
    Student,
    Teacher,
}

fn main() {
    // Explicitly `use` each name so they are available without
    // manual scoping.
    use crate::Stage::{Beginner, Advanced};
    // Automatically `use` each name inside `Role`.
    use crate::Role::*;

    // Equivalent to `Stage::Beginner`.
    let stage = Beginner;
    // Equivalent to `Role::Student`.
    let role = Student;
}

 

기존에 enum으로 정의된 Stage, Role 내부 변형들을 

 

사용하기 위해 Stage::Beginner를 통해 stage라는 식별자에

 

enum 타입형을 할당해야 하지만 use를 통해

 

모듈 이름을 생략합니다.

 

C style enum

 

 

C에서는 각 enum이 어떤 값을 가지게 정의합니다.

 

위에서 보여드린 예시처럼 어떤 리터럴 값을 정의하거나,

 

정의하지 않는다면 0부터 차례대로 할당됩니다.

 

하지만 Rust엔 unit 타입형이 존재하기에 

 

C에서 처럼 쉽게 출력할 수 없습니다.

 

enum Number {
    Zero,
    One,
    Two,
}


fn main() {
    // `enums` can be cast as integers.
    println!("zero is {}", Number::Zero);
    println!("one is {}", Number::One as i32);

}

 

예를 들어 이렇게 타입형과 값이 명시되지 않은

 

Number enum 타입 내 각 변형들은

 

C와 달리 default로 0, 1, 2.. 값을 가지지 않습니다.

 

그래서,

 

    println!("zero is {}", Number::Zero);

 

이러한 구절의 경우 다음과 같은 에러를 발생시킵니다.

 

 

 

 

그런데, enum의 유닛 타입형의 경우 타입 캐스팅은 가능합니다. 

 

enum Number {
    Zero,
    One,
    Two,
}


fn main() {
    // `enums` can be cast as integers.
    println!("zero is {}", Number::Zero as i32);
    println!("one is {}", Number::One as i32);
    println!("two is {}", Number::Two as i32);

}

 

이렇게 각 타입을 i32로 타입 캐스팅을 하면

 

 

값이 출력됩니다.

728x90
반응형

'프로그래밍 언어 > [Rust]' 카테고리의 다른 글

[Rust] Types  (1) 2025.01.03
[Rust] Variable의 특성  (0) 2024.12.30
[Rust] 구조체  (0) 2024.12.30
[Rust] Ownership과 Reference  (0) 2024.12.30
[Rust] 기본 골자  (2) 2024.12.26