2024. 11. 13. 21:48ㆍDevelopment/Rust
Rust에서 자주 사용되는 Option<>
을 살펴보자.
pub fn example_function() -> Result<(), CustomError> {
// Some codes...
let a: Option<&str> = temp.get(1);
Ok(())
}
이 때 a
가 Option<>
타입일 때, 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