Debug 출력
Rust에서 디버그 정보를 출력하기 위해, {:?}, {:#?} 포맷과 dbg!() 매크로 등을 사용한다. 보통 (단순한 타입이 아닌) 복합 타입이나 커스텀 타입의 경우 Debug 포맷팅이나 dbg! 매크로를 사용하여 데이타를 출력하곤 한다.
{:?}, {:#?} 포맷
단순한 타입(Primitive 타입)들은 기본적으로 println!("{}",...) 와 같이 {} 을 사용하여 데이타를 출력할 수 있다. {} 포맷은 std::fmt::Display 을 호출하는 것으로 Primitive 타입들을 이 Display 함수를 기본적으로 구현하고 있다.
배열이나 튜플 같은 좀 복잡한 타입이나 struct와 같은 Custom 타입의 경우는 std::fmt::Display 으로 호출하지 않고, {:?} 혹은 {:#?} 와 같은 포맷으로 호출하는데, 이들 포맷은 std::fmt::Debug 을 사용한다. 배열이나 튜플은 이미 std::fmt::Debug을 구현하고 있어서, {:?} 혹은 {:#?} 과 같은 디버깅 포맷을 사용할 수 있다.
아래 예제에서 배열을 출력할 때, {} 을 사용하면 배열은 std::fmt::Display 을 가지지 않기 때문에 에러가 발생하지만, {:?} (혹은 {:#?}) 을 사용하면 배열의 std::fmt::Debug 이 호출되어 데이타가 출력되게 된다.
fn main() { let arr: [i32; 5] = [1,2,3,4,5]; //println!("{}", arr); // 에러: doesn't implement `std::fmt::Display` println!("{:?}", arr); }
구조체(struct)는 Custom 타입으로 std::fmt::Debug 이 기본적으로 구현되어 있지 않지만, 아래와 같이 struct 정의 위에 #[derive(Debug)] 라는 특성(attribute)을 지정하면, std::fmt::Debug 을 사용할 수 있다. #[derive(Debug)] 이 지정된 구조체는 {:?} 혹은 {:#?}을 사용할 수 있는데, {:?}은 한 라인으로 구조체 필드 데이타를 모두 출력하고, {:#?}는 좀 더 예쁘게 여러 라인으로 한 라인 당 하나의 필드 데이타를 출력한다.
#[derive(Debug)] struct Rect { width: u32, height: u32 } fn main() { let rect = Rect { width: 100, height: 50 }; println!("{:?}", &rect); println!("{:#?}", &rect); }
dbg! 매크로
dbg! 매크로는 파라미터에 지정된 변수의 데이타를 출력하는 디버깅 매크로이다. dbg! 매크로는 Primitive 타입과 #[derive(Debug)]이 지정된 구조체(struct)에 사용할 수 있는데, 해당 변수의 데이타를 출력할 뿐 만 아니라, 데이타 앞에 소스파일명과 라인번호를 함께 출력해 준다.
#[derive(Debug)] struct Rect { width: u32, height: u32 } fn main() { let mut i = 1; i = i + 100; dbg!(i); let rect = Rect { width: 100, height: 50 }; dbg!(&rect); }
위 프로그램을 실행하면, 아래와 같이 소스파일명과 라인수가 데이타 값과 함께 출력된다.
[src/main.rs:10] i = 101 [src/main.rs:16] &rect = Rect { width: 100, height: 50, }