1.2.2 Display
fmt::Debug
는 간결하고 깨끗하게 보긴 어렵기에 출력 형태를 사용자 정의 하는게 많은 장점을 갖는다. 이는 수작업으로 {}
를 출력 기호로 사용하는 fmt::Display
를 구현하여 작업한다. 구현은 아래와 같다:
fmt::Debug
hardly looks compact and clean, so it is often advantageous to
customize the output appearance. This is done by manually implementing
fmt::Display
, which uses the {}
print marker. Implementing it
looks like this:
// (`use`를 통해) `fmt` module을 import해 사용할 수 있게 한다.
// Import (via `use`) the `fmt` module to make it available.
use std::fmt;
// `fmt::Display` 구조체를 정의하여 이를 구현할 수 있게 한다.
// 여기서는 간단하게 `i32`를 포함하는 튜플 구조로 `Structure`란 이름으로 바인드한다.
// Define a structure which `fmt::Display` will be implemented for. This is simply
// a tuple struct containing an `i32` bound to the name `Structure`.
struct Structure(i32);
// `{}` 기호를 사용하기 위해서, `fmt::Display`가 타입에 대해 반드시 구현되어야 한다.
// In order to use the `{}` marker, the trait `fmt::Display` must be implemented
// manually for the type.
impl fmt::Display for Structure {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Write strictly the first element into the supplied output
// stream: `f`. Returns `fmt::Result` which indicates whether the
// operation succeeded or failed. Note that `write!` uses syntax which
// is very similar to `println!`.
write!(f, "{}", self.0)
}
}
fmt::Display
는 fmt::Debug
보다 깨끗할지는 모르겠지만 이는 std
라이브러리에 적용하긴 문제가 있다. 어떻게 모호한 타입도 출력되도록 할 수 있을까? 예를 들어, std
라이브러리가 모든 Vec<T>
를 하나의 스타일을 구현한다고 하면, 다음 둘에 대해 어떤 스타일이 적용되야 할까?
fmt::Display
may be cleaner than fmt::Debug
but this presents
a problem for the std
library. How should ambiguous types be displayed?
For example, if the std
library implemented a single style for all
Vec<T>
, what style should it be? Either of these two?
Vec<path>
:/:/etc:/home/username:/bin
(split on:
)Vec<number>
:1,2,3
(split on,
)
놉, 모든 카입을 위한 이상적인 스타일은 존재하지 않고 std
라이브러리는 하나로 규정될거라 가정하지 않는다. fmt::Display
는 Vec<T>
나 모든 다른 제네릭 컨테이너에는 구현되지 않는다. fmt::Debug
가 이런 제네릭 경우에 사용될 수 있다.
No, because there is no ideal style for all types and the std
library
doesn't presume to dictate one. fmt::Display
is not implemented for Vec<T>
or for any other generic containers. fmt::Debug
must then be used for these
generic cases.
이런 문제는 비 제네릭 컨테이너에는 문제가 아니고 fmt::Dispaly
를 구현할 수 있다.
This is not a problem though because for any new container type which is
not generic,fmt::Display
can be implemented.
use std::fmt; // Import `fmt` // 구조체는 두 숫자를 보관한다. `Debug`가 파생되어 `Display`의 결과와 대조된다. // A structure holding two numbers. `Debug` will be derived so the results can // be contrasted with `Display`. #[derive(Debug)] struct MinMax(i64, i64); // `Display`를 `MinMax`에 구현한다. // Implement `Display` for `MinMax`. impl fmt::Display for MinMax { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Use `self.number` to refer to each positional data point. write!(f, "({}, {})", self.0, self.1) } } // 비교용으로 필드가 이름을 갖는 구조체를 정의한다. // Define a structure where the fields are nameable for comparison. #[derive(Debug)] struct Point2 { x: f64, y: f64, } // 비슷하게 Point2를 위해 구현한다. // Similarly, implement for Point2 impl fmt::Display for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // 사용자 정의를 통해 `x`와 `y`만 표시되도록 한다. // Customize so only `x` and `y` are denoted. write!(f, "x: {}, y: {}", self.x, self.y) } } fn main() { let minmax = MinMax(0, 14); println!("Compare structures:"); println!("Display: {}", minmax); println!("Debug: {:?}", minmax); let big_range = MinMax(-300, 300); let small_range = MinMax(-3, 3); println!("The big range is {big} and the small is {small}", small = small_range, big = big_range); let point = Point2 { x: 3.3, y: 7.2 }; println!("Compare points:"); println!("Display: {}", point); println!("Debug: {:?}", point); // 에러. `Debug`와 `Display` 둘이 구현되었지만 `{:b}`는 // `fmt::Binary`의 구현이 요구된다. 이는 동작하지 않는다. // Error. Both `Debug` and `Display` were implemented but `{:b}` // requires `fmt::Binary` to be implemented. This will not work. // println!("What does Point2D look like in binary: {:b}?", point); }
그래서, fmt::Display
는 구현되었지만 fmt::Binary
는 아니라면, 사용할 수 없다. std::fmt
는 이런 traits
을 많이 보유하고 있으며 이들은 각자 그 자신의 구현을 요구한다. 여기 std::fmt
에 더 상세한 내용이 있다.
So, fmt::Display
has been implemented but fmt::Binary
has not, and
therefore cannot be used. std::fmt
has many such traits
and
each requires its own implementation. This is detailed further in
std::fmt
.
Activity
상기 예제의 출력을 확인한 후에, Point2
구조체를 견본으로 삼아 Complex 구조체를 예제에 추가해보자. 동일한 방식으로 출력하면, 출력은 아래와 같이 나오게 될 것이다:
After checking the output of the above example, use the Point2
struct as
guide to add a Complex struct to the example. When printed in the same
way, the output should be:
Display: 3.3 + 7.2i
Debug: Complex { real: 3.3, imag: 7.2 }