Rust 输出到命令行
println! 的格式占位符、调试输出、以及格式化家族。
Key Points`{}` 走 `Display`,`{:?}` 走 `Debug`,`{:#?}` 是美化版 Debug。
四种输出宏
| Macro | Target | Newline |
|---|---|---|
print! | stdout | 不换行 |
println! | stdout | 换行 |
eprint! | stderr | 不换行 |
eprintln! | stderr | 换行 |
Rust
fn main() {
print!("不换行");
println!(",然后换行");
eprintln!("这条去 stderr");
}Output
不换行,然后换行
这条去 stderr占位符
Rust
fn main() {
let name = "Rust";
let n = 42;
let pi = 3.14159;
println!("{} 版本 {}", name, n);
println!("{0} {0} {1}", "重复", "参数");
println!("{name} 可以直接插变量");
println!("{:?}", vec![1, 2, 3]);
println!("{:#?}", vec![1, 2, 3]);
println!("{:05}", n);
println!("{:.2}", pi);
println!("{:>8}|{:<8}|{:^8}", "右", "左", "中");
println!("{:b} {:o} {:x} {:X}", 255, 255, 255, 255);
println!("{:e}", 12345.678);
}Output
Rust 版本 42
重复 重复 参数
Rust 可以直接插变量
[1, 2, 3]
[
1,
2,
3,
]
00042
3.14
右|左 | 中
11111111 377 ff FF
1.2345678e4Inline {name} arrived in Rust 1.58 — shorter than println!("{}", name) and impossible to mismatch. It only takes identifiers, not arbitrary expressions.
Display 与 Debug
Rust
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("{:?}", p);
println!("{:#?}", p);
// println!("{}", p); // 编译错误:Point 没有实现 Display
}Output
Point { x: 1, y: 2 }
Point {
x: 1,
y: 2,
}#[derive(Debug)] generates Debug for {:?}. Display ({}) must be written by hand — there is no universal answer for how a value should read to a human.
Rust
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
println!("{}", Point { x: 1, y: 2 });Output
(1, 2)格式化到字符串
Rust
let s = format!("{} + {} = {}", 1, 2, 3);
println!("{}", s);
// 追加到已有字符串
let mut buf = String::from("结果:");
use std::fmt::Write;
write!(buf, "{}", 42).unwrap();
println!("{}", buf);Output
1 + 2 = 3
结果:42The number of
{} must match the arguments — a mismatch is a compile error, not a runtime panic. That is where Rust's format macros beat C's printf.四种输出宏
| 宏 | 输出到 | 换行 |
|---|---|---|
print! | stdout | 不换行 |
println! | stdout | 换行 |
eprint! | stderr | 不换行 |
eprintln! | stderr | 换行 |
Rust
fn main() {
print!("不换行");
println!(",然后换行");
eprintln!("这条去 stderr");
}Output
不换行,然后换行
这条去 stderr占位符
Rust
fn main() {
let name = "Rust";
let n = 42;
let pi = 3.14159;
println!("{} 版本 {}", name, n);
println!("{0} {0} {1}", "重复", "参数");
println!("{name} 可以直接插变量");
println!("{:?}", vec![1, 2, 3]);
println!("{:#?}", vec![1, 2, 3]);
println!("{:05}", n);
println!("{:.2}", pi);
println!("{:>8}|{:<8}|{:^8}", "右", "左", "中");
println!("{:b} {:o} {:x} {:X}", 255, 255, 255, 255);
println!("{:e}", 12345.678);
}Output
Rust 版本 42
重复 重复 参数
Rust 可以直接插变量
[1, 2, 3]
[
1,
2,
3,
]
00042
3.14
右|左 | 中
11111111 377 ff FF
1.2345678e4{name} 这种内联写法是 Rust 1.58 加的,比 println!("{}", name) 短且不容易漏参数。变量名之外还能内联表达式:println!("{}", x + 1) 不行,但 println!("{} {}", x, x + 1) 可以。
Display 与 Debug
Rust
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("{:?}", p);
println!("{:#?}", p);
// println!("{}", p); // 编译错误:Point 没有实现 Display
}Output
Point { x: 1, y: 2 }
Point {
x: 1,
y: 2,
}#[derive(Debug)] 自动实现 Debug,让你能用 {:?} 打印。Display({})必须手写,因为「怎么给人看」没有通用答案。
Rust
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
println!("{}", Point { x: 1, y: 2 });Output
(1, 2)格式化到字符串
Rust
let s = format!("{} + {} = {}", 1, 2, 3);
println!("{}", s);
// 追加到已有字符串
let mut buf = String::from("结果:");
use std::fmt::Write;
write!(buf, "{}", 42).unwrap();
println!("{}", buf);Output
1 + 2 = 3
结果:42println! 里的 {} 数量必须和参数数量一致,多一个少一个都是编译错误(不是运行时 panic)。这是 Rust 格式化宏比 C 的 printf 安全的地方。