형식을 지정하는 출력
러스트에서 출력 관련 기능은 std::fmt
에 정의된 몇 개의
macro
로 처리합니다.
format!
: 형식 지정 문자열을String
에 출력합니다.print!
:format!
과 동일하지만, 출력을 콘솔 (io::stdout) 에 합니다.println!
:print!
과 동일하지만, 개행 문자를 덧붙여줍니다.eprint!
:format!
과 동일하지만, 표준 오류 스트림 (io::stderr) 에 출력합니다.eprintln!
:eprint!
과 동일하지만, 개행 문자를 덧붙여줍니다.
이들은 모두 동일한 형식 지정자를 사용합니다. 러스트는 컴파일 시점에 형식 지정이 올바른지 여부도 검사합니다.
fn main() { // 일반적으로, {}는 자료형에 관계없이 주어진 인자로 대치됩니다. // 이때, 인자들은 문자열로 변환됩니다. println!("{} 번째 날", 31); // 자료형 표시(suffix)가 없으므로 31은 i32 형이 됩니다. 31 의 자료형을 바꾸려면 // 자료형 표시(suffix)를 해주면 됩니다. 31i64 라고 하면 i64 형이 됩니다. // 중괄호를 이용해서 다양한 방법으로 형식을 지정할 수 있는데, 다음처럼 // 인자의 위치를 이용할 수 있습니다. println!("{0}야 얘는 내 친구 {1}야. {1}야 이쪽은 {0}야", "영희", "철수"); // 이름을 이용할 수도 있습니다. println!("{subject} {verb} {object}", object="the lazy dog", subject="the quick brown fox", verb="jumps over"); // 역주) 한글도 잘 됩니다. println!("{주어} {목적어} {동사}.", 동사="한다", 주어="내가", 목적어="코딩을"); // `:` 의 뒤에 특별한 형식을 지정할 수도 있습니다. println!("{:b}명의 사람들 중 {}명 만이 이진법을 알고, 나머지 반은 모른다", 2, 1); println!("10진수: {}", 69420); // 69420 println!(" 2진수 (binary): {:b}", 69420); // 10000111100101100 println!(" 8진수 (octal): {:o}", 69420); // 207454 println!("16진수 (hexadecimal): {:x}", 69420); // 10f2c // 폭을 지정해서 오른편 정렬을 할 수도 있습니다. 다음 코드의 출력은 // " 1" 이 됩니다. 즉, 공백문자 5개가 나온 후에 "1"이 출력됩니다. println!("{number:>width$}", number=1, width=6); //println!("{number:>5}", number=1); // 공백대신 숫자 0을 넣을 수도 있습니다. 다음 코드는 "000001"을 출력합니다. println!("{number:0>width$}", number=1, width=6); //println!("{number:0>5}", number=1); // 00001 // 반대쪽에 넣을 수도 있습니다. 다음 코드는 "100000"을 출력합니다. println!("{number:0<width$}", number=1, width=6); //println!("{number:0<5}", number=1); // 10000 // 역주) 역시 한글도 잘 됩니다. println!("{숫자:>폭$}", 숫자=1, 폭=6); println!("{숫자:>0폭$}", 숫자=1, 폭=6); // 러스트는 인자의 숫자가 맞는지 검사도 해줍니다. println!("내 이름은 {0}요. {1} {0}.", "본드"); // FIXME ^ 위 코드에서 빠진 인자 "제임스"를 추가해주세요. // fmt::Display를 정의한 타입만 `{}`를 이용해 출력할 수 있습니다. // 사용자 정의 타입은 기본적으로 정의하고 있지 않고요. // 한개의 `i32` 를 가지고 있는 `Structure`라는 구조체를 생성해봅니다. #[allow(dead_code)] struct Structure(i32); // `Structure`가 fmt::Display를 가지고 있지 않기 때문에, 이 코드는 컴파일조차 // 되지 않습니다. println!("이 구조체 {}는 출력되지 않을겁니다.", Structure(3)); // FIXME ^ 위 코드를 코멘트로 막아주세요. // 러스트 1.58부터, 근처의 변수로부터 매개변수를 가져올 수 있습니다. // 여기에서는 위에서처럼 " 1", 1 앞에 4개의 공백을 출력합니다. let number: f64 = 1.0; let width: usize = 5; println!("{number:>width$}"); // 역주) 역시, 한글도 잘 됩니다. 그리고 사실 변수명도 한글로 잘 됩니다. let 숫자: f64 = 1.0; let 폭: usize = 6; println!("{숫자:->폭$}"); // -----1 }
std::fmt
에는 문자열 출력에 관련된 많은 트레잇(traits)
이 있습니다. 다음은 두개의 중요한 트레잇입니다.
fmt::Debug
:{:?}
에 사용됩니다. 디버깅에 사용합니다.fmt::Display
:{}
를 사용됩니다. 보기 편하게 출력 형식을 지정하는데 사용합니다.
위의 예제에서는 표준 라이브러리가 지원하는 자료형들을 출력했기 때문에 fmt::Display
를 사용했습니다.
사용자 정의 자료형을 위해서는 추가 작업이 필요합니다.
만약 fmt::Display
트레잇을 구현해주면 자동으로 ToString
트레잇이 구현되고,
해당 자료형을 String
으로 변환(convert)
할 수 있게됩니다.
중간의 #[allow(dead_code)]
는 바로 다음에 오는 모듈에만 적용되는 속성입니다.
Activities
- 위 코드에서 두 개의 이슈(FIXME 라고 된 부분들)를 수정하고 오류없이 실행되게 해보세요.
println!
매크로의 소수점 표시 기능을 이용해서원주율의 근사치는 3.142이다.
를 출력해보세요. 이를 위한 파이값은let pi = 3.141592
라고 정의해주세요. (힌트:std::fmt
문서에서 소수점 표시(Precision) 항목을 참고하세요.)
참고:
std::fmt
, 매크로(macros)
, 구조체(struct)
,
트레잇(traits)
, 미사용 코드(dead_code)