Rust의 매크로 시스템은 코드를 생성하고 추상화하는 강력한 방법을 제공합니다.
매크로는 코드를 생성하거나 특정 패턴에 따라 코드를 변형하는 데 사용되는 메타 프로그래밍 기술입니다.
Rust에서는 매크로를 사용하여 코드 중복을 줄이고, 가독성을 향상시키며, 유연한 추상화를 구현할 수 있습니다.
매크로는 주로 컴파일 시간에 코드를 생성하거나 수정하는 작업에 사용됩니다. (ex. println!
)
선언형 매크로는 매크로 규칙을 사용하여 코드를 생성하는 매크로입니다.
macro_rules!
키워드를 사용하여 선언형 매크로를 정의할 수 있습니다.
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
fn main() {
let v = vec![1, 2, 3];
println!("v: {:?}", v);
}
프로시저 매크로는 Rust의 컴파일러에 플러그인으로 동작하는 함수입니다.
프로시저 매크로는 주로 속성(attribute)에 사용되며, 소스 코드를 받아 변형된 소스 코드를 반환합니다.
프로시저 매크로를 정의하려면 proc_macro
라이브러리를 사용하고, 별도의 크레이트로 구성해야 합니다.
// 프로시저 매크로를 정의하는 크레이트입니다.
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("안녕하세요, 여기는 {}입니다.", stringify!(#name));
}
}
};
gen.into()
}
// 프로시저 매크로를 사용하는 크레이트입니다.
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
Pancakes::hello_macro();
}
Rust의 매크로는 패턴 매칭을 통해 매개 변수를 추출하고, 규칙에 따라 코드를 생성합니다.
매크로에서 패턴 매칭을 사용하려면 다음 구문을 사용합니다.
$name:expr
: 표현식(Expressions) 매치$name:ident
: 식별자(Identifiers) 매치$name:ty
: 타입(Types) 매치$name:pat
: 패턴(Patterns) 매치$name:stmt
: 문장(Statements) 매치$name:block
: 블록(Blocks) 매치$name:meta
: 메타 데이터(Meta-data) 매치$name:tt
: 토큰 트리(Token Tree) 매치$name:item
: 항목(Items) 매치또한, 매크로에서 사용할 수 있는 반복자 구문도 있습니다.
$(...)*
: 0회 이상 반복$(...)+
: 1회 이상 반복macro_rules! create_function {
($func_name:ident) => (
fn $func_name() {
println!("함수 {}가 호출되었습니다.", stringify!($func_name));
}
);
}
create_function!(foo);
create_function!(bar);
fn main() {
foo();
bar();
}
이렇게 매크로를 사용하여 코드 생성 및 추상화를 구현하면, 유연한 프로그래밍을 할 수 있고, 가독성 및 유지보수성을 높일 수 있습니다.
매크로의 핵심은 패턴 매칭과 규칙을 통해 코드를 재사용하고, 확장성을 높이는 것입니다.