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
'Back-End > Rust' 카테고리의 다른 글
[Rust] 15장(완) - Rust 코드 작성 - 프로젝트 생성, 코드 예제 (3) | 2025.08.13 |
---|---|
[Rust] 13장 메모리 (2) | 2025.08.09 |
[Rust] 12장 비동기 프로그래밍 (1) | 2025.08.05 |
[Rust] 11장 고차 함수 (0) | 2025.04.04 |
[Rust] 10장 트레이트 (0) | 2025.03.25 |