매크로 문법

macro_rules! say_hello {
    ($name: expr) => {
        println!("hello {}", $name);
    };
}

fn main() {
    say_hello!("Rust");
}
  • 러스트에서 매크로는 macro_rules! 키워드로 정의한다
  • $ 기호는 매크로 인자를 나타낸다
macro_rules! add {
    ($a: expr, $b: expr) => {
        $a + $b
    };
}

fn main() {
    println!("{}", add!(1, 2));
}
  • a, b는 각각 표현식을 받아들이는 패턴이다
  • 컴파일 타임에 컴파일러는 매크로를 소스코드를 본문에 추가한다

매칭

($matcher) => {$expansion}
  • 위에서 say_hello나 add 매크로는 위와 같은 형태로 정의했다
($matcher) => ($expansion)

[$matcher] => {$expansion}

{$matcher} => {$expansion}
  • 위와 같이 다양한 서로 다른 괄호를 사용해서 매크로를 정의할 수도 있다

메타 변수

$name: designator
  • 매크로의 메타변수는 위와 같은 형태로 표현한다
  • name은 메타변수의 이름, designator는 일치시킬 문법의 형태를 나타낸다
designator내용
expr표현식
ident식별자
tt토큰 트리
ty타입
pat패턴
macro_rules! create_function {
    ($func_name: ident) => {
        fn $func_name() {
            println!{"function: {:?}()", stringify!($func_name)}
        }
    };
}

create_function!(ident_func);

fn main() {
    ident_func();
}
  • 예를 들어, ident를 사용해서 함수를 정의하는 매크로를 만들 수 있다
macro_rules! create_accessors {
    ($name: ident, $type: ty, $setter:ident) => {
        fn $name(&self) -> &$type {
            &self.$name
        }

        fn $setter(&mut self, value: $type) {
            self.$name = value;
        }
    };
}

 #[derive(Debug)]
struct Person {
    name: String,
    age: i32
}

impl Person {
    create_accessors!(name, String, set_name);
    create_accessors!(age, i32, set_age);
}

fn main() {
    let mut person = Person {name: String::from("name"), age: 33};

    person.set_name(String::from("newname"));
    person.set_age(22);

    println!("{:?}", person);
}
  • 위 처럼, getter, setter의 구현을 매크로를 활용해서 간단하게 만들 수 있다

반복

macro_rules! declare_with_values {
    ($( $var:ident = $val:expr ),*) => {
        $(let mut $var = $val;)*
    };
}

fn main() {
    declare_with_values!(a = 3, b = 7, c = 12);
    println!("{} {} {}", a, b, c);
}
  • 러스트 매크로의 matcher는 반복을 포함할 수 있다
    • 즉, 여러개의 변수를 반복해 받을 수 있다
  • $(...) sep * rep의 형태로 정의할 수 있다
    • 위 예제에서는
    • $(...)은 $( $var:ident = $val:expr ),
    • sep,
    • rep* 이다
지시자내용
$(...)일치시킬 패턴과 designator를 포함
sep각 반복 사이의 구분자
,(쉼표), :(세미콜론), +(더하기)와 같은 토큰이 들어갈 수 있다
rep반복의 종류
*(별표)는 0회 이상의 반복, +(더하기)는 1회 이상의 반복을 의미한다
macro_rules! multi_var {
    ($($var:ident: $type:ty), *) => {
        $(
            let mut $var: $type = Default::default();
        )*
    };
}

fn main() {
    multi_var!(x: i32, y: f64, z: String);
    // let mut x: i32 = Default::default();
    // let mut y: f64 = Default::default();
    // let mut z: String = Default::default();
}
  • 위 예제처럼 여러개 변수를 정의하는데 사용할 수도 있다

0개의 댓글