
이번에는 러스트 매크로에 대해 알아보겠다. 기본적으로 러스트는 다른 언어들과 다르게 매크로도 컴파일 된다. 잘 알려진 C언어의 매크로는 다음과 같다.
#define MAIN(argc, argv) main(int argc, char *argv[])
int MAIN(argc, argv) {
return 0;
}
이런식으로 단순 치환이 된다.
하지만 러스트는 이런 단순 치환에 목적을 둔 매크로라기 보단 언어 자체가 장황해서 단축시켜 사용할 목적으로 만들어진 매크로이기 때문에 따로 문법을 익혀야 한다.
다음은 expr에서 From trait이 구현된 새로운 String을 생성하는 매크로이다.
macro_rules! S {
($e:expr) => {
String::from($e)
}
}
let foo = S!("hello");
다른 언어의 매크로들과는 다르게 메타변수라는게 있다.
$e:expr 부분이 메타변수이다.
expr 타입을 가진 어떤 러스트 문법도 저 변수에 들어갈 수 있다는 얘기이다.
macro_rules! twice {
($e:expr) => {
{
$expr;
$expr;
}
}
}
twice!(println!("hello world!"));
// output
// hello world
// hello world
물론 expr 이외에 여러가지 메타변수들이 있다.
아래는 메타변수들 matcher의 종류이다
expr: 모든 표현식ident: 식별자path: 경로 표현식. 예를 들어, std::collections::HashMap 같은 모듈, 크레이트, 아이템의 경로ty: 타입. 예를 들어, i32, f64, Vec<T>, &str 등의 타입들block: 중괄호 {}로 둘러싸인 코드 블록. 블록 내에는 여러 문장과 표현식이 포함될 수 있음stmt: 문장. 선언문, 표현문 등이 해당됨pat: 패턴. match 문이나 if let 구문에서 사용되는 패턴 매칭item: 아이템을 매칭합니다. fn, struct, enum, 상수 등 최상위 구성 요소meta: 속성 내용. 예를 들어, #[derive(Debug)]에서 derive(Debug) 부분이 해당됨tt: 토큰 트리. 거의 모든 종류의 구문을 포함할 수 있는 가장 유연한 매처임이런 메타변수들을 가지고 라이브러리를 만들 때 확장성 있는 매크로와 함께 나만의 라이브러리를 만들 수 있을 것이다.
한 포스트에서는 패턴 매쳐들을 다루기 힘드니 여러 포스트로 나눠서 소개하고 써보도록 하겠다.