자바스크립트를 허용해주세요.
[ 자바스크립트 활성화 방법 ]
from Mohon Aktifkan Javascript!
 

[Rust] 14장 매크로

728x90

✅ 1.매크로 종류

  • 선언적 매크로 (macro_rules!)
    • 템플릿 기반으로 토큰을 매칭해 코드 생성, 반복($( )*), 선택($( ) ?), 캡쳐($ident:expr 등) 지원, 컴파일 타임에 단순 반복/패턴 생성에 최적함
  • 프로시저 매크로 (procedural macros)
    • 세 가지 형태: derive 매크로(구조체*열거형에 자동 impl 생성), 속성(attribute), 매크로(아이템에 추가 동작), 함수형(function-like) 매크로(my_macro!(...))
    • 더 강력한 토큰스트림을 받아 파싱·분석·출력 가능, 보통 proc-macro, syn, quote, proc-macro2 사용

✅ 2. macro_rules! 기본 예제

// 간단한 vec! 비슷
macro_rules! my_vec {
    ( $( $x:expr ), * $(,)? ) => {
        {
            let mut v = Vec::new();
            $(
                v.push($x);
            )*
            v
        }
    }
}

fn main() {
    let a = my_vec![1, 2, 3];
    println!("{:?}", a) // [1, 2, 3]
}
  • $( ) 반복과 $(,)? 같은 후행 콤마 허용 패턴을 자주 사용

✅ 3. macro_rules! 팁

  • 매칭 우선순위: 위에서부터 내려와 구체적인 패턴을 먼저 놓을 수 있음
  • 재귀/tt-muncher: 복잡한 파서를 만들 때 토큰-트리(tt) 분해 방식(재귀적 매크로 호출)을 사용
  • 모듈 경계: macro_rules!는 선언된 스코프에 따라 가시성이 달라, #[macro_export]로 크레이트 루트에 노출할 수 있음
  • 디버깅: 매크로가 확장된 코드를 보려면 cargo expand를 사용

✅ 4. 프로시저 매크로 

  • 구조
    • 별도 크레이트 만들기: proc-macro = true in Cargo.toml
    • proc_macro::TokenStream 받음 -> 파싱(보통 syn) -> 코드 생성(보통 quote) -> TokenStream 반환
    • ex) derive 매크로 골격
// 워크 페이스 최상위 Cargo.toml 파일
[workspace]
members = [
    "my_macro",
    "main_app"
]
rust_blog/
├── Cargo.toml           # 위 workspace 멤버 지정
├── my_macro/
│   ├── Cargo.toml
│   └── src/lib.rs
└── main_app/
    ├── Cargo.toml
    └── src/main.rs
// main_app/Cargo.toml
[package]
name = "main_app"
version = "0.1.0"
edition = "2024"
 

[dependencies]
my_macro = { path = "../my_macro" }
// main_app/src/main.rs

use my_macro::MyTrait;
 
trait MyTrait {
    fn hello();
}


#[derive(MyTrait)]  
struct MyStruct;  

fn main() {
    MyStruct::hello();  
}
// my_macro/Cargo.toml
[package]
name = "my_macro"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true 

[dependencies]
quote = "1.0"
syn = { version = "2.0", features = ["full"]}
// my_macro/src/lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

#[proc_macro_derive(MyTrait)]
pub fn my_trait_derive(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    let name = &ast.ident;

    let gen = quote! {
        impl MyTrait for #name {
            fn hello() {
                println!("Hello from MyTrait for {}", stringify!(#name));
            }
        }
    };
    gen.into()
}
cargo build 
cargo run # myapp으로 이동해서

✅ 5. 주의사항 / 안 좋은 패턴

  • 오용 시 가독성/디버깅 비용 증가: 매크로가 많아질 수록 코드 읽기가 어려워짐
  • 매크로 오류 메시지: 매크로 내부에 발생한 오류가 뿌려질 때 위치 추적이 헷갈릴 수 있음, compile_error!로 명확히해야함
  • 위생(hygiene): 매크로가 생성한 식별자 충돌을 방지하는 룰이 있음(대부분 자동), 일부 상황에 의도적으로 식별자를 노출하려면 ident 등으로 처리
  • 불안정한 기능: 일부 조합(ex.concat_idents!)은 불안정/비추천

✅ 6. 추천 워크플로우 / 도구

  • cargo expand로 매크로 확장 결과 학인.
  • 프로시저 매크로 개발 시 syn(+ visit/fold)과 quote 사용
  • 테스트: 생성과 코드를 실제 컴파일/테스트로 검증(유닛테스트에 작은 케이스 추가)

 

 

GitHub - Koras02/rust-tutorial: https://thinky.tistory.com/category/Back-End/Rust

https://thinky.tistory.com/category/Back-End/Rust. Contribute to Koras02/rust-tutorial development by creating an account on GitHub.

github.com

 

728x90
LIST