파생 특성 사용

완료됨

사용자 지정 형식을 실제로 사용하는 것은 약간 어려울 수 있습니다. 이 간단한 Point 구조체를 다른 Point 인스턴스와 비교하거나 터미널에 표시할 수 없습니다. 이러한 어려움 때문에 derive 특성을 사용하여 구조체에 대해 자동으로 새 항목이 생성되도록 할 수 있습니다.

제네릭 형식의 단점

다음 코드 예제를 살펴보세요.

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 4, y: -3 };

    if p1 == p2 { // can't compare two Point values!
        println!("equal!");
    } else {
        println!("not equal!");
    }

    println!("{}", p1); // can't print using the '{}' format specifier!
    println!("{:?}", p1); //  can't print using the '{:?}' format specifier!

}

위의 코드는 3가지 이유로 실패합니다. 다음 출력을 참조하세요.

    error[E0277]: `Point` doesn't implement `std::fmt::Display`
      --> src/main.rs:10:20
       |
    10 |     println!("{}", p1);
       |                    ^^ `Point` cannot be formatted with the default formatter
       |
       = help: the trait `std::fmt::Display` is not implemented for `Point`
       = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
       = note: required by `std::fmt::Display::fmt`
       = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

    error[E0277]: `Point` doesn't implement `Debug`
      --> src/main.rs:11:22
       |
    11 |     println!("{:?}", p1);
       |                      ^^ `Point` cannot be formatted using `{:?}`
       |
       = help: the trait `Debug` is not implemented for `Point`
       = note: add `#[derive(Debug)]` or manually implement `Debug`
       = note: required by `std::fmt::Debug::fmt`
       = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

    error[E0369]: binary operation `==` cannot be applied to type `Point`
      --> src/main.rs:13:11
       |
    13 |     if p1 == p2 {
       |        -- ^^ -- Point
       |        |
       |        Point
       |
       = note: an implementation of `std::cmp::PartialEq` might be missing for `Point`

    error: aborting due to 3 previous errors#+end_example

Point 형식에서는 다음 특성을 구현하지 않기 때문에 이 코드는 컴파일되지 않습니다.

  • {:?} 형식 지정자를 사용하여 형식을 지정할 수 있도록 하는 Debug 특성은 프로그래머 지향 디버깅 컨텍스트에서 사용됩니다.
  • {} 형식 지정자를 사용하여 형식을 지정할 수 있도록 하는 Display 특성은 Debug와 비슷합니다. 그러나 Display는 사용자에게 표시되는 출력에 보다 적합합니다.
  • 구현자가 같은지 비교할 수 있도록 하는 PartialEq 특성

파생 사용

다행히 각 필드에서 #[derive(Trait)] 특성을 구현하는 경우 해당 특성을 사용하여 Rust 컴파일러에서 DebugPartialEq 특성을 자동으로 구현할 수 있습니다.

#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

Rust의 표준 라이브러리는 최종 사용자를 위한 것이므로 Display 특성에 대한 자동 구현을 제공하지 않습니다. 따라서 코드는 여전히 컴파일되지 못합니다. 그러나 해당 줄을 주석으로 처리하는 경우 이제 이 코드는 다음과 같은 출력을 생성합니다.

    not equal!
    Point { x: 1, y: 2 }

그렇지만 형식에 대한 Display 특성을 직접 구현할 수 있습니다.

use std::fmt;

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

이제 코드가 컴파일됩니다.

    not equal!
    (1, 2)
    Point { x: 1, y: 2 }

Rust Playground 링크에서 이 예제의 코드를 확인하세요.