매크로는 Rust 프로그래머의 도구 상자에서 강력한 부분을 차지해요. macros by example은 그 강력함에 비교적 간단하게 접근하는 방법이고요. 하나 만들어 봐요!
매크로란 무엇일까요? 위키백과는 이렇게 설명해요:
컴퓨터 과학에서 매크로(macro, "macroinstruction"의 줄임말이고 그리스어 μακρός '길다'에서 왔어요)는 특정 입력 시퀀스(보통 문자 시퀀스)가 정의된 절차에 따라 대체 출력 시퀀스(역시 보통 문자 시퀀스)로 어떻게 매핑되어야 하는지를 지정하는 규칙이나 패턴이에요. 매크로 사용을 특정 시퀀스로 구체화(변환)하는 이 매핑 과정을 매크로 확장이라고 해요.
명쾌하네요! 그런데 좀 더 구체적으로 말하자면, 매크로는 컴파일 시점에 코드를 생성할 수 있게 해 주는 특별한 문법이에요. 매크로는 컴파일 시점 계산에 쓸 수도 있지만, 대개는 코드를 추상화하는 또 하나의 방법일 뿐이에요. 예를 들어, 아마 이미 println!()과 vec![]를 써 봤을 거예요. 이 둘은 각각 임의의 개수만큼 인자를 받기 때문에 단순한 함수로는 표현할 수 없어요. 반면에, 항상 완전히 표준적인 Rust 코드로 확장되지요. 관심이 있다면 cargo expand 하위 명령으로 내 코드에서 매크로가 확장된 결과를 확인할 수 있어요.
Rust의 매크로에 대해 더 알고 싶다면, The Rust Book에 이에 관한 좋은 챕터가 있어요.
vec![] 매크로를 쓰면 임의 길이의 Vec을 인라인으로 만들 수 있어요. 하지만 Rust에는 HashMap을 인라인으로 만드는 방법이 없어요. hashmap!() 매크로를 작성해서 이 문제를 해결해 봐요.
예를 들어, 이 라이브러리를 쓰는 사람은 hashmap!('a' => 3, 'b' => 11, 'z' => 32)라고 쓸 수 있어요. 이것은 다음 코드로 확장되어야 해요:
{
let mut hm = HashMap::new();
hm.insert('a', 3);
hm.insert('b', 11);
hm.insert('z', 32);
hm
}
참고로 maplit 크레이트에는 이 연습 문제를 완벽하게 해결해 주는 매크로가 있어요. 이 크레이트를 쓰지 말고 직접 풀이를 구현해 봐요. 그리고 그 소스를 보기 전에 먼저 스스로 한번 시도해 봐요.