Rust macro 활용

2024. 11. 13. 21:48Development/Rust

728x90
반응형

Rust에서 자주 사용되는 Option<>을 살펴보자.

pub fn example_function() -> Result<(), CustomError> {
    // Some codes...


    let a: Option<&str> = temp.get(1);


    Ok(())
}

이 때 aOption<> 타입일 때, a의 값이 존재하면 unwrap()을 통해 T를 가져오고, 존재하지 않다면 error를 return한다 가정한다. 그렇다면 코드 상에서는 아래와 같이 표현될 수 있을 것이다.

pub fn example_function() -> Result<(), CustomError> {
    // Some codes...


    let a: Option<&str> = temp.get(1);
    if a.is_none() {
        return CustomError::AIsNone{}
    }
    let a = a.unwrap();


    Ok(())
}

Rust에서 Option<>이 자주 사용되다 보니 값을 사용할 때마다 Some(T)가 존재하는지 확인하고, 존재하지 않을 때의 예외 처리를 수행한 뒤에 값을 가져와야 한다. 예외 처리가 더 복잡할 시에는 match도 꺼내들어야 한다.

개발자의 귀찮음을 이겨낼 수 있도록 이렇게 자주 반복적으로 사용되는 부분에 있어 macro를 사용하면 귀찮음을 조금 더 덜 수 있다. Macro이 이론적인 설명과 예시는 링크에 한글로 상세히 설명되어 있으니 참고하면 좋을것 같다.

그래서 위의 a의 처리와 같은 예시에서 macro를 활용해본다.

#[macro_export]
macro_rules! option_unwrap_or_return {
    ( $e:expr, $err:expr ) => {
        match $e {
            Some(x) => x,
            None => return Err($err),
        }
    }
}

이렇게 macro를 선언하고 나면

pub fn example_function() -> Result<(), CustomError> {
    // Some codes...

    let a = option_unwrap_or_return!(temp.get(1), CustomError::AIsNone{});

    Ok(())
}

이런 식으로 한줄로 표현될 수 있고, 타이핑 횟수가 줄어 들 것이다.

비슷하게, 어떤 외부 function을 수행한 결과를 받아 처리하는 상황이 있을 수 있다.

pub fn example_function() -> Result<(), CustomError> {
    // Some codes...

    let a = use_function();
    if !a.is_ok() {
        return CustomError
    }
    let a = a.unwrap();

    Ok(())
}

fn use_function() -> Result<u64, CustomError> {
    // Some codes...

    Ok(number)
}

Macro를 아래와 같이 선언하면,

#[macro_export]
macro_rules! unwrap_or_return {
    ( $e:expr ) => {
        match $e {
            Ok(x) => x,
            Err(err) => return Err(CustomError::Invalid{ error: err.to_string() }),
        }
    }
}
pub fn example_function() -> Result<(), CustomError> {
    // Some codes...

    let a: u64 = unwrap_or_return!(use_function());

    Ok(())
}

fn use_function() -> Result<u64, CustomError> {
    // Some codes...

    Ok(number)
}

앞선 Option<>의 경우처럼 한줄로 간략해지고, 예외 처리도 한번에 할 수 있다. Macro를 잘 사용하면 코드 중복도 덜어내고 읽기 쉬운 Rust 코드가 되지 않을까한다.

참고
https://rinthel.github.io/rust-lang-book-ko/appendix-04-macros.html

728x90
반응형