Rust 의 형식화된 출력

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 Rust 의 형식화된 출력 기능을 설명합니다. std::fmt 모듈은 출력 작업을 처리하기 위해 format!, print!, println!, eprint!, 그리고 eprintln!과 같은 매크로를 제공합니다. 이러한 매크로를 사용하면 해당 인수로 대체되는 자리 표시자를 사용하여 텍스트를 형식화할 수 있습니다. 위치 인자 및 명명된 인자를 사용할 수 있으며, 형식 지정 문자를 사용하여 다양한 형식 지정을 적용할 수 있습니다. 또한 매크로는 텍스트 정렬, 숫자 패딩, 그리고 소수점 숫자의 정밀도 설정을 지원합니다. fmt::Display 트레이트는 사용자 친화적인 방식으로 텍스트를 형식화하는 데 사용되며, fmt::Debug 트레이트는 디버깅 목적으로 사용됩니다. Rust 는 또한 컴파일 시간에 형식 지정의 정확성을 검사합니다. 또한, fmt::Display 트레이트를 구현하면 자동으로 ToString 트레이트가 구현되며, 사용자 정의 타입은 출력이 가능하도록 fmt::Display 트레이트를 구현해야 합니다. 이 랩에는 형식화된 출력 매크로와 트레이트를 사용하는 연습을 위한 활동도 포함되어 있습니다.

참고: 랩에서 파일 이름을 지정하지 않은 경우, 원하는 파일 이름을 사용할 수 있습니다. 예를 들어, main.rs를 사용하고 rustc main.rs && ./main으로 컴파일하고 실행할 수 있습니다.

형식화된 출력

출력은 std::fmt에 정의된 일련의 매크로(macros)에 의해 처리되며, 그 중 일부는 다음과 같습니다.

  • format!: 형식화된 텍스트를 String에 씁니다.
  • print!: format!과 동일하지만 텍스트가 콘솔 (io::stdout) 에 출력됩니다.
  • println!: print!와 동일하지만 줄 바꿈이 추가됩니다.
  • eprint!: print!와 동일하지만 텍스트가 표준 오류 (io::stderr) 에 출력됩니다.
  • eprintln!: eprint!와 동일하지만 줄 바꿈이 추가됩니다.

모두 동일한 방식으로 텍스트를 구문 분석합니다. 게다가 Rust 는 컴파일 시간에 형식 지정의 정확성을 검사합니다.

fn main() {
    // 일반적으로 `{}` 는 모든 인수로 자동 대체됩니다. 이들은 문자열화됩니다.
    println!("{} days", 31);

    // 위치 인수를 사용할 수 있습니다. `{}` 안에 정수를 지정하면
    // 어떤 추가 인수가 대체될지 결정됩니다. 인수는 형식 문자열 바로 뒤 0 부터 시작합니다.
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // 명명된 인수도 마찬가지입니다.
    println!("{subject} {verb} {object}",
             object="the lazy dog",
             subject="the quick brown fox",
             verb="jumps over");

    // `:` 뒤에 형식 지정 문자를 지정하여 다른 형식을 호출할 수 있습니다.
    println!("Base 10:               {}",   69420); // 69420
    println!("Base 2 (binary):       {:b}", 69420); // 10000111100101100
    println!("Base 8 (octal):        {:o}", 69420); // 207454
    println!("Base 16 (hexadecimal): {:x}", 69420); // 10f2c
    println!("Base 16 (hexadecimal): {:X}", 69420); // 10F2C

    // 지정된 너비로 텍스트를 오른쪽 정렬할 수 있습니다. 이렇게 하면 "    1"이 출력됩니다.
    // (총 너비가 5 가 되도록 공백 4 개와 "1" 하나).
    println!("{number:>5}", number=1);

    // 숫자를 추가 0 으로 채울 수 있습니다.
    println!("{number:0>5}", number=1); // 00001
    // 그리고 부호를 뒤집어 왼쪽 정렬할 수 있습니다. 이렇게 하면 "10000"이 출력됩니다.
    println!("{number:0<5}", number=1); // 10000

    // `$` 를 추가하여 형식 지정자에서 명명된 인수를 사용할 수 있습니다.
    println!("{number:0>width$}", number=1, width=5);

    // Rust 는 올바른 수의 인수가 사용되었는지도 확인합니다.
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ 누락된 인수 추가: "James"

    // `fmt::Display` 를 구현하는 타입만 `{}` 로 형식화할 수 있습니다. 사용자 정의
    // 타입은 기본적으로 `fmt::Display` 를 구현하지 않습니다.

    #[allow(dead_code)] // 사용하지 않는 모듈에 대해 경고하는 `dead_code` 비활성화
    struct Structure(i32);

    // `Structure` 가 `fmt::Display` 를 구현하지 않기 때문에
    // 이 코드는 컴파일되지 않습니다.
    // println!("This struct `{}` won't print...", Structure(3));
    // TODO ^ 이 줄의 주석을 해제해 보세요

    // Rust 1.58 이상에서는 주변 변수에서 인수를 직접 캡처할 수 있습니다.
    // 위와 마찬가지로 "    1", 공백 4 개와 "1"이 출력됩니다.
    let number: f64 = 1.0;
    let width: usize = 5;
    println!("{number:>width$}");
}

std::fmt에는 텍스트 표시를 제어하는 많은 트레이트(traits)가 포함되어 있습니다. 두 가지 중요한 트레이트의 기본 형태는 다음과 같습니다.

  • fmt::Debug: {?:} 마커를 사용합니다. 디버깅 목적으로 텍스트를 형식화합니다.
  • fmt::Display: {} 마커를 사용합니다. 보다 우아하고 사용자 친화적인 방식으로 텍스트를 형식화합니다.

여기서는 std 라이브러리가 이러한 타입에 대한 구현을 제공하기 때문에 fmt::Display를 사용했습니다. 사용자 정의 타입에 대한 텍스트를 출력하려면 더 많은 단계가 필요합니다.

fmt::Display 트레이트를 구현하면 자동으로 ToString 트레이트가 구현되어 타입을 String으로 변환할 수 있습니다.

43 번째 줄에서 #[allow(dead_code)]는 그 뒤의 모듈에만 적용되는 [속성 (attribute)]입니다.

활동

  • 위의 코드에서 오류가 발생하지 않도록 문제를 수정하세요 (FIXME 참조).
  • Structure 구조체를 형식화하려는 줄의 주석을 해제해 보세요 (TODO 참조).
  • Pi is roughly 3.142를 출력하는 println! 매크로 호출을 추가하여 표시되는 소수점 자릿수를 제어하세요. 이 연습을 위해 let pi = 3.141592를 pi 의 추정치로 사용하세요. (힌트: 표시할 소수점 자릿수를 설정하려면 std::fmt 문서를 확인해야 할 수 있습니다.)

요약

축하합니다! 형식화된 출력 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.