티스토리 뷰
매크로
매크로는 다른 코드를 작성하는 코드이다.
이 개념은 메타 프로그래밍으로 잘 알려져 있다.
코드의 내용을 출력해주는 print!와 Vector배열을 정의하는 vec!도 매크로이다.
이 모든 매크로들은 수동으로 코드를 작성하지 않고도 많은 코드를 생산할 수 있다.
메타프로그래밍은 함수와 비슷하게 작성해야 할 코드의 양을 줄여주지만, 함수가 할 수 없는 일도 할 수 있다.
함수 시그니처는 해당 함수가 갖는 parameter와 갯수 타입을 선언해야 하는 반면, 매크로는 parameter의 개수를 가변적으로 처리할 수 있다.
// ex
println!("hello");
println!("{}", hello);
함수와 매크로의 또다른 차이는, 매크로 정의는 함수와 달리 모듈의 "네임스페이스에 소속되지 않는다"는 것이다.
이로 인하여 외부 Crate 사용시 발생하는 예기치 않은 naming충돌 방지를 위하여 외부 Crate를 스코프 내로 가져오는 동시에 #[macro_use] annotation을 사용하여 가져올 매크로를 명시해야 한다.
함수 대신 매크로 코드를 사용하는 것에 대한 단점도 있다.
매크로를 구현한다는 것은 러스트 코드를 만들어내는 코드를 작성한다는 것인데, 이는 추상화 계층을 하나 더 만들어 낸다는 의미이기 때문에 함수 정의에 비하여 코드가 복잡해진다.
일반적인 메타프로그래밍을 위한 macro_rules!를 사용하는 선언적 매크로
rust에서는 선언적 매크로의 형태로 가장 널리 사용된다.
이는 macro by example, macro_rules! 매크로, 아니면 그냥 매크로 라고 불리기도 한다.
선언적 매크로는 rust의 match 표현식과 유사하게 작성할 수 있다.
#[macro_export]
macro_rules! vec {
($ ($x: expr), *) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*temp_vec
}
};
}
vec! 매크로 정의를 간략화한 모습이다.
std library 내 vec!매크로는 메모리의 정확한 양을 미리 할당하는 코드가 포함되어 있다.
이 코드에서는 간략화하여 표현했다.
#[macro_export] annotation은 정의한 매크로가 들어있는 Crate를 누군가 import 했을 때, 해당 매크로를 사용할 수 있도록 해준다. 즉 export 해준다. 이 annotation을 사용하지 않을 경우 이 크레이트를 dependency로 갖는 누군가,
#[macro_use] annotation을 사용하더라도 해당 매크로는 스코프 내로 가져와지지 않는다.
매크로는 macro_rules! 와 매크로 이름으로 정의할 수 있다.
위의 예시에서 vec!의 본문 구조는 match 표현식 구조와 유사하다. 여기서 ( $ ($x: exper), *) 패턴과 그 뒤로 따라오는 =>, 그리고 해당 패턴에 연관된 코드 블록으로 이루어진 갈래 하나를 찾는다. 패턴이 매칭될 경우, 해당 패턴에 대하여 연관된 코드가 반환된다.
매크로 정의에 사용되는 패턴 문법은 아래 링크에서 확인할 수 있다.
https://doc.rust-lang.org/reference/macros.html#macros
- 괄호 쌍이 전체 패턴을 둘러싼다.
- 달러기호($)뒤에 괄호 쌍이 오며, 배치할 코드에서 사용하기 위해, 괄호 안 패턴과 일치하는 값을 캡쳐한다.
- $() 내부에 $x: exper가 있는데, 이는 어떤 rust 표현식과도 매치되며, 그에 $x라는 이름을 부여하는 기능을 한다.
- $()에 따라오는 쉼표는 $() 내부에 캡처되어 매치된 코드뒤에 나타날 수 있는 리터럴 쉼표 구분 문자를 나타낸다.
- 쉼표 뒤의 * 는 자신 앞에 위치한 0개 이상 패턴을 지정한다.
- 위에서 작성한 매크로 vec에서 vec![1, 2, 3]; 으로 호출할 경우 $x 패턴은 1, 2, 3 세번의 표현식에 맞추어 세번 매칭된다.
- 패턴 갈래와 연관된 본문 코드를 살펴보자면 $() 내부의 temp_vec.push() 코드는 패턴에서 $()에 매치되는 횟수만큼 반복되어 생성되고, 코드 내 $x는 각각 매치된 표현식으로 대체된다.
매크로는 인수 개수가 어느 만큼이건, 인수가 어떤 타입이건 가리지 않고 특정한 요소들을 포함할 벡터를 만들어내는 코드를 생성할 수 있다.
매크로 관련해서 다양한 예시이다.
https://danielkeep.github.io/tlborm/book/index.html
참고.
https://rinthel.github.io/rust-lang-book-ko/appendix-04-macros.html
'Rust-Language' 카테고리의 다른 글
trait 다른 타입 간 허용 (0) | 2021.09.15 |
---|---|
life time, 라이프 타임 (0) | 2021.09.12 |
trait: 공유 동작 정의 (0) | 2021.09.08 |
반복자, iterator (0) | 2021.09.03 |
Closure, 클로저 함수 (0) | 2021.08.05 |