10. Rust 데이터 유형에 강력한 성능을 제공하는 Enum
Rust의 열거형(enums)에 대해 이야기해보려고 합니다. Rust에서의 열거형은 C 언어의 열거형과는 다르게 하스켈(Haskell)의 대수적 데이터 타입과 더 비슷합니다.
열거형을 정의할 때는 enum
키워드를 사용하며, 대문자로 카멜케이스로 된 이름과 해당하는 변형들을 중괄호 안에 나열합니다.
Defining Enum
이렇게 정의한 열거형을 단순히 사용할 수도 있습니다. 이 경우 C 언어의 열거형과 비슷한 방식으로 사용할 수 있습니다. 열거형에 데이터와 메서드를 연결하는 것이 Rust 열거형의 진정한 힘입니다.
Basic Enum Usage
아래의 DispenserItem
예시를 살펴봅시다.
1
2
3
4
5
6
enum DispenserItem {
Empty,
Ammo(u8),
Things(String, i32),
Place { x: i32, y: i32 },
}
여기서 DispenserItem
은 Empty
처럼 데이터가 없는 이름있는 변형, Ammo
처럼 단일 데이터, Things
처럼 데이터가 튜플이나 익명 구조체로 묶인 변형 등 여러 가지 형태가 될 수 있습니다.
이렇게 선언한 값들은 다음과 같이 사용 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum DispenserItem {
Empty,
Ammo(u8),
Things(String, i32),
Place { x: i32, y: i32 },
}
fn main() {
// DispenserItem 열거형 사용 예제
let item1 = DispenserItem::Empty;
let item2 = DispenserItem::Ammo(10);
let item3 = DispenserItem::Things(String::from("Gadget"), 42);
let item4 = DispenserItem::Place { x: 10, y: 20 };
// 각각의 항목 출력
match item1 {
DispenserItem::Empty => println!("Item is Empty"),
DispenserItem::Ammo(amount) => println!("Item is Ammo with amount: {}", amount),
DispenserItem::Things(name, value) => println!("Item is Things: {} - {}", name, value),
DispenserItem::Place { x, y } => println!("Item is Place at ({}, {})", x, y),
}
}
Implementing Functions and Methods
또한, 열거형에 함수와 메서드를 구현할 수 있습니다. 열거형은 제네릭과 함께 사용될 수도 있습니다. 표준 라이브러리에서 자주 사용되는 Option
열거형을 예로 들어 보겠습니다.
Using Enums with Generics: Option
Option
열거형은 값이 존재할 수도, 존재하지 않을 수도 있는 경우에 사용됩니다.
1
2
3
4
enum Option<T> {
Some(T),
None,
}
여기서 T
는 임의의 타입을 나타냅니다. 이러한 제네릭 열거형은 많은 경우에서 유용하게 사용됩니다. Option
은 값을 갖는 Some
변형과 값을 갖지 않는 None
변형으로 구성됩니다.
Some enum
을 if let Some(xx)
구문과 match
를 이용해 사용하는 예제 코드입니다.
다양한 방법으로 Some enum
에서 값을 가지고 올 수 있는 것 을 알 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
use std::collections::HashMap;
fn main() {
let mut x = None;
x = Some(5);
if let Some(b) = x {
println!("1. value is {}", b);
}
x.is_some(); // true
x.is_none(); // false
match x {
Some(value) => {
println!("2. {}", value)
},
None => {
println!("2. None value")
}
}
let x2 = match x {
Some(value) => {
value + 1
},
None => {
0
}
};
println!("3. {}", x2);
}
Handling Enum with Patterns
열거형은 다양한 데이터를 나타낼 수 있기 때문에 패턴을 사용하여 이를 처리해야 합니다. 단일 변형을 확인하려면 “if let” 표현식을 사용합니다.
1
2
3
4
5
if let Some(value) = some_option {
println!("Value: {}", value);
} else {
println!("Option is None");
}
모든 변형을 처리해야 하는 경우에는 match
표현식을 사용합니다.
1
2
3
4
match result {
Ok(value) => println!("Value: {}", value),
Err(error) => println!("Error: {}", error),
}
Special Enums in Standard Library
표준 라이브러리에서 자주 사용되는 두 가지 특별한 열거형에 대해 조금 더 자세히 살펴보겠습니다.
Option: Handling Absence
Option
은 값의 존재 여부를 나타냅니다. Some
과 None
은 어떤 값이 있는지 없는지를 나타냅니다.
1
2
3
4
5
let some_value: Option<i32> = Some(5);
let none_value: Option<i32> = None;
println!("Is some_value Some? {}", some_value.is_some()); // true
println!("Is none_value None? {}", none_value.is_none()); // true
Result: Dealing with Errors
Result
는 작업의 결과 또는 오류를 나타냅니다. 주로 IO 모듈에서 자주 사용됩니다.
1
2
3
4
5
6
7
8
use std::fs::File;
let file_result = File::open("example.txt");
match file_result {
Ok(file) => println!("File opened successfully: {:?}", file),
Err(error) => println!("Error opening file: {}", error),
}
이렇게 함으로써, 열거형을 사용하여 다양한 상황을 다룰 수 있습니다. Rust에서 열거형은 데이터를 구조화하고 처리하는 강력한 도구입니다