매크로: 코드를 작성하는 코드
학습 목표: Rust에서 매크로가 왜 필요한지(오버로딩 및 가변 인자 미지원 보완) 이해하고, 가장 기본적인
macro_rules!사용법을 익힙니다. 또한derive매크로를 통해 반복적인 코드를 줄이는 법과 디버깅의 필수 도구인dbg!매크로 활용법을 배웁니다.
1. Rust에 매크로가 필요한 이유
C#은 메서드 오버로딩과 가변 인자(params)를 지원하지만, Rust는 이를 지원하지 않습니다. 대신 매크로를 사용하여 컴파일 타임에 코드를 확장함으로써 동일한 효과를 냅니다.
| 기능 | C# 기능 | Rust 대응 매크로 |
|---|---|---|
| 가변 인자 출력 | Console.WriteLine(...) | println!(...) |
| 컬렉션 초기화 | new List<int> {1, 2, 3} | vec![1, 2, 3] |
| 포맷 문자열 | string.Format(...) | format!(...) |
| 조건부 실행 | #if DEBUG | cfg!(debug_assertions) |
2. 매크로 식별법: ! 접미사
코드 끝에 !가 붙어 있다면 그것은 함수가 아니라 매크로입니다. 매크로는 일반 함수보다 더 강력하며, 가변 인자를 받거나 컴파일 타임에 특별한 검사를 수행할 수 있습니다.
todo!(): "나중에 구현할 예정"임을 표시하며 실행 시 패닉을 발생시킵니다.assert_eq!(a, b): 두 값이 다르면 에러 메시지와 함께 중단합니다.dbg!(expr): 코드 실행 중에 파일명, 줄 번호, 식의 결과값을 출력하는 매우 유용한 디버깅 도구입니다.
3. 파생(Derive) 매크로: 지루한 작업의 자동화
구조체 위에 #[derive(...)]를 붙이면 컴파일러가 알아서 필요한 기능을 구현해 줍니다. C#에서 IEquatable이나 ICloneable을 일일이 구현하던 수고를 덜어줍니다.
#![allow(unused)] fn main() { #[derive(Debug, Clone, PartialEq, Default)] struct User { name: String, age: u32, } // 이제 User는 자동으로 출력, 복제, 비교, 기본값 생성이 가능해집니다. }
💡 실무 팁: dbg! 매크로의 마법
println!보다 dbg!를 쓰세요. dbg!는 값을 출력할 뿐만 아니라 그 값을 다시 반환합니다. 따라서 코드 흐름을 방해하지 않고 중간에 끼워 넣을 수 있습니다.
#![allow(unused)] fn main() { // [전] let x = a + b; println!("x: {}", x); let y = x * 2; // [후] let y = dbg!(a + b) * 2; // 한 줄로 확인과 연산을 동시에! }