카테고리 없음

Rust 매크로(Macro) 기초와 사용법

mystory55801 2025. 6. 6. 15:52

Rust에서 매크로(Macro)란 무엇인가요?

Rust의 매크로(Macro)는 반복적인 코드나 패턴을 컴파일 타임에 자동으로 생성할 수 있는 기능입니다. 함수처럼 보이지만, 매크로는 실제로 코드를 생성하는 도구이며, 러스트 컴파일러가 매크로를 확장한 뒤에 컴파일을 진행합니다.

Rust에는 크게 두 가지 종류의 매크로가 존재합니다:

  • 선언적 매크로(declarative macro): macro_rules!를 사용
  • 절차적 매크로(procedural macro): 함수처럼 동작하며, 더 복잡한 구조 처리 가능

macro_rules!를 사용한 선언적 매크로

가장 기본적인 매크로는 macro_rules!를 사용하는 방식입니다. 이는 특정 패턴에 맞는 입력을 받아서 코드 조각으로 치환합니다.


macro_rules! say_hello {
    () => {
        println!("Hello, Rust!");
    };
}

fn main() {
    say_hello!(); // Hello, Rust!
}

say_hello!는 함수처럼 보이지만, 실제로는 컴파일 타임에 코드가 삽입됩니다. 이 방식으로 반복 코드나 상용구를 줄일 수 있습니다.

매크로에 인자 전달하기

매크로는 다양한 인자를 받아 동작할 수 있습니다. 예를 들어, 여러 값을 받아 출력하는 매크로를 만들어보겠습니다.


macro_rules! print_values {
    ( $( $x:expr ),* ) => {
        $(
            println!("값: {}", $x);
        )*
    };
}

fn main() {
    print_values!(10, "Rust", true);
}

$( $x:expr ),* 패턴은 Rust의 반복 매크로 문법입니다. 여러 인자를 처리할 때 매우 유용하며, 함수형 프로그래밍의 가변 인자처럼 작동합니다.

매크로의 장점: 반복 제거와 성능

매크로는 다음과 같은 상황에서 매우 유용합니다:

  • 반복되는 코드 패턴 제거
  • 에러 메시지 자동 생성
  • 컴파일 타임 성능 최적화
  • DSL(Domain Specific Language) 설계

예를 들어, 구조체 필드를 자동으로 초기화하거나 로깅 매크로를 만들 때 유용합니다.


macro_rules! create_point {
    ($x:expr, $y:expr) => {
        Point { x: $x, y: $y }
    };
}

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = create_point!(3, 4);
    println!("({}, {})", p.x, p.y);
}

매크로와 함수의 차이점

Rust 매크로는 일반 함수와 다음과 같은 차이가 있습니다:

  • 매크로는 컴파일 타임에 동작하며, 함수는 런타임에 호출됨
  • 매크로는 타입에 상관없이 작동하며, 제네릭보다 더 유연할 수 있음
  • 매크로는 코드 블록 전체를 조작 가능

그러나 너무 많은 매크로 사용은 코드 가독성을 떨어뜨릴 수 있으므로, 적절한 사용이 중요합니다.

매크로 디버깅 팁: 매크로가 확장된 코드 보기

매크로가 실제로 어떻게 확장되는지 확인하려면, 아래 명령어를 사용할 수 있습니다:


$ cargo rustc -- -Zunpretty=expanded

이 기능은 Rust nightly 버전에서만 사용할 수 있으며, 매크로가 컴파일러에 의해 어떻게 확장되는지 디버깅에 매우 유용합니다.

절차적 매크로: 더 강력한 매크로 기능

더 복잡한 로직이나 구조체/함수 자동 생성이 필요할 경우 절차적 매크로(procedural macro)를 사용할 수 있습니다. 이를 위해 별도의 크레이트에서 proc_macro를 사용하며, 대표적인 예로 #[derive(...)]가 있습니다.

예시: 사용자 정의 #[derive]


// 예: #[derive(Debug)] 처럼 동작하는 매크로는 procedural macro
#[derive(MyTrait)]
struct MyStruct;

절차적 매크로는 파서와 토큰 스트림을 다루는 만큼 복잡하지만, 강력한 코드 자동화 기능을 제공합니다.

결론: Rust 매크로는 코드 생산성을 높이는 도구

Rust의 macro_rules! 매크로는 간단한 패턴 매칭부터 반복 코드 생성까지 다양한 작업을 손쉽게 처리할 수 있습니다. 반복적인 로직을 줄이고, 실수를 방지하며, 컴파일 타임 성능을 높이는 데 매우 유용합니다.

처음에는 매크로 문법이 어렵게 느껴질 수 있지만, 간단한 매크로부터 연습하고 점차 응용하다 보면 매우 강력한 도구임을 알게 될 것입니다. 특히 함수형 프로그래밍 스타일이나 도메인 특화 언어(DSL)를 작성할 때 매크로는 꼭 필요한 요소입니다.