Rust Option의 메서드 알아보기

2023. 4. 1. 17:58Language/Rust

오늘은 Rust의 Option에 대해 알아보도록 하겠습니다.

Option

Rust에서 기본적으로 null이 존재하지 않습니다. 그래서 널 포인터 참조와 같은 에러는 발생하지 않습니다.

하지만 Null을 표현하는 방법이 필요할 때가 있기 때문에 Rust에서는 Option<T>라는 Enum 타입을 제공합니다.

enum Option<T> {
    Some(T),
    None,
}

Option 안에는 두 개의 variant(종류)가 존재합니다.

  • Some : 값을 가지는 variant
  • None : 값을 가지지 않는 variant

예제 설명

fn divide(dividend: i32, divisor: i32) -> Option<i32> {
    if divisor == 0 {
        None
    } else {
        Some(dividend / divisor)
    }
}


fn main() {
    let result = divide(10, 2);
    match result {
        Some(x) => println!("Result is {}", x),
        None => println!("Cannot divide by zero"),
    }
}

위 예제를 보도록 하겠습니다.

fn divide()의 경우 값을 0으로 나누게 되면 에러가 발생하기 때문에 divisor가 0이 들어 올 경우 None을 리턴하고 0이 아니면 나눈값을 리턴합니다.

리턴값은 Option입니다. 여기서 None이 리턴 될 경우 "Cannot divide by zero"로 예외 처리가 가능합니다.

Option 함수

Option의 경우 여러 함수가 존재합니다. 이 함수들로 반환값에 대해 여러 동작을 할 수 있도록 코드를 만들 수 있습니다.

is_some() / is_none()

is_some은 Option의 값이 Some인지 여부를 확인하는 메서드 입니다. 이 메서드는 bool 값을 반환하면 값이 Some인 경우 true, None일 경우 false를 반환합니다.

is_none은 Option의 값이 None인지 여부를 확이하는 메서드 입니다. 이 메서드는 bool 값을 반환하면 값이 None인 경우 true, Some일 경우 true를 반환합니다.

fn main() {
    let some_option:Option<i32> = Some(1);

    if some_option.is_some() {
        println!("some_option is Some");
    }

    let none_option:Option<i32> = None;

    if none_option.is_none() {
        println!("none_option is None");
    }
}

unwrap()

Option의 값은 Some아니면 None입니다. 이 때 Some 안에는 로 제너릭 값이 들어가게 되는데 이때 unwrap을 통해 값을 추출합니다.

unwrap()은 값이 None일 때는 런타입 오류를 일으키기 때문에 이 메서드를 사용 할 때는 주의가 필요합니다.

fn divide(dividend: i32, divisor: i32) -> Option<i32> {
    if divisor == 0 {
        None
    } else {
        Some(dividend / divisor)
    }
}
fn main() {
    let result = divide(10, 0);

    let x = result.unwrap();
    println!("Result is {}", x);
}

위 예제는 panic을 일으키는 예제입니다. result가 None이기 때문에 런타입 에러가 발생합니다. 그래서 아래의 예제와 같이 None에 대한 체크가 필요합니다.

fn divide(dividend: i32, divisor: i32) -> Option<i32> {
    if divisor == 0 {
        None
    } else {
        Some(dividend / divisor)
    }
}
fn main() {
    let result = divide(10, 0);

    if result.is_some() {
        let x = result.unwrap();
        println!("Result is {}", x);
    }

    match result {
        Some(x) => println!("Result is {}", x),
        None => println!("Result is None"),
    }   
}

위와 같이 is_some을 사용하여 체크 후 값을 unwrap() 하는 방법이 있고 가장 많이 사용되는 match를 사용하는 방법이 있습니다.

map()

map의 경우는 Option의 값이 Some일 때만 연산을 수행하고, 결과를 Some으로 감싸는 메서드 입니다.

Option의 값이 None인 경우는 그대로 None을 반환합니다.

fn main() {
    let some_option: Option<i32> = Some(5);

    let option_mapped = some_option.map(|num| num + 1);

    match option_mapped {
        Some(x) => println!("result is {}", x),
        None => println!("result is None"),
    }
}

map 메서드는 Some일때만 동작하기 때문에 클로저를 사용하여 Some일 경우 값의 + 1을 하여 Some(num+1)을 리턴하도록 만들었습니다.

그래서 Some이라면 result is 6가 됩니다.

filter()

filter()은 Option의 값이 Some일 때만 연산을 수행하고 값을 필터링하여 반환하는 메소드입니다.

Option값이 Non인 경우 None을 그대로 반환 합니다.


fn main() {
    let some_option: Option<i32> = Some(5);

    let option_filtered = some_option.filter(|num| num == &1);

    match option_filtered {
        Some(x) => println!("result is {}", x),
        None => println!("result is None"),
    }
}

filter(|num| num == &1) 이 부분에서 &1의 은 1을 차용 한다는 뜻입니다.

num은 5이기 때문에 None이 필터링 됩니다.

or_else()

or_else() 메서드는 Option 값이 None 일 경우 클로저를 호출하여 대체 값을 생성합니다. 만약 Option이 Some 인 경우에는 해당 값을 그대로 반환합니다.

fn main() {
    let none_option: Option<i32> = None;

    let option_or_else = none_option.or_else(|| Some(5));

    let result = option_or_else.unwrap();

    println!("result is {}", result);
}

none_option의 값은 None이므로 Some(5)를 반환합니다.

unwrap_or_else()

unwrap_or_else 메서는 None이 주어지 경우 클로저를 호출하여 대체 값을 생성합니다. 위 or_else()와 다른 점은 or_else은 Some을 리턴하지만 unwrap_or_else()는 값을 리턴합니다.

fn main() {
    let none_option: Option<i32> = None;

    let unwrpped = none_option.unwrap_or_else(|| 5);

    println!("unwrapped is {}", unwrpped);
}

'Language > Rust' 카테고리의 다른 글

Rust 설치 및 VS Code 셋팅(Linux, Debian)  (0) 2023.04.26
Web Assembly 만들어 보기  (0) 2023.04.15
Rust 소스 코드 문서화  (0) 2023.03.21
Rust 열거형(Enum)  (0) 2023.03.20
Rust Struct(구조체)  (1) 2023.03.12