Rust 공부

  • 2022-03-02 현재 Learn Rust 진행중
  • 종종 까먹는데 이름다음에 ! 가 붙으면 macro라는 뜻이다

Formatted print 섹션

  • traits ? : 특성 으로 번역됨
    • 관련 문서 : Formatting traits
    • text 의 display를 관리하는 method
    • print 문에서 문자열 내에서 {:b} 형태로 표현되는 것은 marker 이고
    • {:b}의 display는 fmt::Binary trait 에서 관리하게된다
  • 기본적으로 중요한 두가지 traits는 아래와 같다
    • fmt::Debug: {:?} marker를 사용하며, 디버깅 목적으로 text를 format한다
    • fmt::Display: {} marker를 사용하며, 사용자 친화적인 방식으로 text를 format한다

Debug

  • 관련 문서 : Debug
  • std::fmt의 formatting traits를 사용하려는 모든 type들은 프린트가능해지려면 구현이 필요하다
  • 자동적인 implementation은 std library에 있는 type들에 대해서만 제공된다
  • 모든 다른 type들은 수동적으로 구현되어야 한다
  • fmt::Debug trait는 이것을 매우 직관적으로 만든다
  • 모든 types는 fmt::Debug의 implementation 은 파생(drive, 즉 automatically create) 할 수있다
    • 반면에 fmt::Display의 경우는 수동적으로 구현되어야 한다
  • fmt::Debug는 모든 것을 printable하게 만들수는 있지만 어떻게 보여줄지에 대한 조정은 할 수 없다

Display

  • 관련 문서 : Display
  • fmt::Debug는 컴팩트하고 깔끔하게 보이지 않기에, 출력모양을 조정하는 것이 좋다
  • 이것은 fmt::Display를 수동적으로 구현함으로써 가능하다
  • 구현하면 아래처럼 된다
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    // 'use'를 통해서, 'fmt' 모듈을 import 해서 'fmt' 모듈 사용이 가능해진다
    use std::fmt;
      
    // 'fmt::Display'가 구현될 structure를 정의한다. 
    // 이건 'Structure'로 이름붙은 tuple 구조체로 'i32'를 포함한다
    struct Structure(i32);
      
    // '{}' marker를 사용하기 위해, 위 type에 대해 'fmt::Display' trait 가 직접 구현되어야 한다
    impl fmt::Display for Structure {
      // 이 trait는 정확한 함수 signature 로 정의되는 'fmt' method가 필요하다
      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // 제공받은 출력 스트림 'f'에 첫번째 element를 정확히 작성한다
        // operation의 성공이나 실패를 표시하는 'fmt::Result'를 반환한다
        // 'write!'가 'println!'과 매우 유사한 문법을 사용하고 있음을 주목하라
        write!(f, "{}", self.0);
    }
      
    
  • fmt::Displayfmt::Debug보다 명확하겠지만, std library에 문제를 제공한다
    • 모호한 type들은 어떻게 표시되는가?
  • 예를 들면, std library가 모든 Vec<T>에 대해 single style을 구현했다면, 어떤 style을 가져야 하나?
  • 아래 두가지중 하나가 될까?
    • Vec<path>: /:/etc:/home/username:/bin (split on :)
    • Vec<number>: 1,2,3 (split on ,)
  • 아니다. 모든 type에 이상적인 style은 없고 std library는 하나를 지시한다고 가정하지 않는다
  • fmt::DisplayVec<T>나 다른 일반적인 container에 대해 구현되지 않았다.
  • 이런 일반적인 case들에 대해서는 fmt::Debug가 사용되어야 한다
  • 그렇지만 이건 문제점이 아니다.
    • 일반적이지 않은 새로운 container type에대해 fmt::Display가 구현될 수 있기 때문이다
    • (역자주) 변수를 container라는 용어로 부르고 있다. 색다르네..

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      
      use std::fmt; // Import 'fmt'
      
      // 두개의 숫자를 갖는 구조체이다. 
      // 결과물이 'Display'와 대조되도록 'Debug'에서 파생시킨다
      #[derive(Debug)]
      struct MinMax(i64, i64);
      
      // 'MinMax'에 대한 'Display'를 구현한다
      impl fmt::Display for MinMax {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          // 각각의 위치기반 데이타 포인트를 참조하도록 'self.숫자' 형식을 사용한다
          wirte!(f, "({}, {})", self.0, self.1)
        }
      }
      
      // 비교를 위해 필드들에 이름을 부여할수 있는 구조체를 정의한다
      #[derive(Debug)]
      sturct Point2D {
        x: f64;
        y: f64;
      }
      
      // 비슷하게 'Point2D'를 위한 'Display'를 구현한다
      impl fmt::Display for Point2D {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          // 'x'와 'y'만 표시되도록 지정한다 
          wirte!(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,
                 bing = big_range);
                     
        let point = Point2D { x: 3.3, y: 7.2 };
            
        println!("Compare points:");
        println!("Display: {}", point);
        println!("Debug: {:?}", point);
           
        // 에러가 발생한다. 'Debug' 와 'Display'가 모두 구현되었으나, 
        // '{:b}'의 사용은 'fmt::Binary'가 구현을 요구한다. 아래 줄은 동작하지 않을것이다
        // println!("What does Point2D look like in binary: {:b}?", point);
            
      }
      
    • 위와 같이, fmt::Display가 구현되었지만 fmt::Binary는 구현되지 않았기에 사용할 수 없다.
    • std::fmt는 이런 traits를 많이 가지고 있고 각자의 구현을 요구한다.
    • std::fmt에 더 자세한 내용이 있다

Display 숙제 (Activity)