macro_rules!
Rust는 메타프로그래밍을 가능하게 하는 강력한 매크로 시스템을 제공합니다. 이전 장들에서 보았듯이, 매크로는 이름이 느낌표 !로 끝난다는 점을 제외하면 함수와 비슷해 보입니다. 하지만 함수 호출을 생성하는 대신, 매크로는 프로그램의 나머지 부분과 함께 컴파일되는 소스 코드로 확장됩니다. 그러나 C나 다른 언어의 매크로와 달리, Rust 매크로는 문자열 전처리가 아닌 추상 구문 트리(AST)로 확장되므로, 예상치 못한 연산자 우선순위 버그가 발생하지 않습니다.
매크로는 macro_rules! 매크로를 사용하여 생성됩니다.
// `say_hello`라는 이름의 간단한 매크로입니다.
macro_rules! say_hello {
// `()`는 매크로가 인자를 취하지 않음을 나타냅니다.
() => {
// 매크로는 이 블록의 내용으로 확장됩니다.
println!("안녕하세요!")
};
}
fn main() {
// 이 호출은 `println!("안녕하세요!")`로 확장됩니다.
say_hello!()
}
그렇다면 왜 매크로가 유용할까요?
-
반복하지 마세요(DRY, Don’t repeat yourself). 여러 곳에서 서로 다른 타입에 대해 유사한 기능이 필요할 수 있는 경우가 많습니다. 종종 매크로를 작성하는 것은 코드 반복을 피하는 유용한 방법입니다. (이에 대해서는 나중에 자세히 다룹니다)
-
도메인 특화 언어(DSL, Domain-specific languages). 매크로를 사용하면 특정 목적을 위한 특정 구문을 정의할 수 있습니다. (이에 대해서는 나중에 자세히 다룹니다)
-
가변 인자 인터페이스. 때로는 가변적인 개수의 인자를 취하는 인터페이스를 정의하고 싶을 때가 있습니다. 예를 들어
println!은 형식 문자열에 따라 인자를 몇 개든 취할 수 있습니다! (이에 대해서는 나중에 자세히 다룹니다)