PS:该内容由AI总结,注意甄别
Rust std::fmt 模块完全指南
文档来源:Rust文档网(Rust Wiki) 的 std::fmt 模块
1. 模块概述
std::fmt 是 Rust 标准库中负责文本格式化与打印的核心模块,提供了类型安全、灵活可控的格式化能力,支持从简单字符串拼接到底层流写入的全场景需求。其核心设计目标是:
- 兼容类似 C 的
printf、Python 的str.format等常见格式化语法,降低学习成本; - 编译时校验格式字符串与参数的匹配性,避免运行时错误;
- 支持自定义类型的格式化逻辑,满足不同场景(用户展示、调试、日志)的输出需求。
2. 核心格式化宏
std::fmt 提供了 7 个核心宏,覆盖“字符串生成”“终端输出”“自定义流写入”等场景,具体差异如下表:
| 宏名称 | 核心功能 | 输出目标 | 关键特性 | 示例代码 |
|---|---|---|---|---|
format! |
将格式化结果生成 String 字符串 |
内存字符串(无 IO 操作) | 最基础的格式化宏,无副作用 | let s = format!("Hello, {}", "Rust"); // s = "Hello, Rust" |
print! |
格式化内容输出到标准输出流(stdout) | 终端(默认) | 不自动追加换行符 | print!("Value: {} ", 42); // 终端输出 "Value: 42 " |
println! |
同 print!,但末尾自动追加换行符 \n
|
标准输出流(stdout) | 适合逐行输出 | println!("Line: {}", 1); // 终端输出 "Line: 1\n" |
eprint! |
格式化内容输出到标准错误流(stderr) | 终端(默认,用于错误信息) | 不自动追加换行符 | eprint!("Error: "); // 终端输出错误提示 "Error: " |
eprintln! |
同 eprint!,末尾自动追加换行符 \n
|
标准错误流(stderr) | 适合错误日志逐行输出 | eprintln!("File not found"); // 终端输出错误行 "File not found\n" |
write! |
将格式化内容写入实现 Write 特质的目标(如文件、缓冲区) |
自定义流(如 Vec<u8>) |
需手动处理 fmt::Result
|
let mut buf = String::new(); write!(buf, "Num: {}", 10)?; |
writeln! |
同 write!,末尾自动追加换行符 \n
|
自定义流 | 需手动处理 fmt::Result
|
writeln!(buf, "Line: {}", 2)?; // buf 中追加 "Line: 2\n" |
3. 格式化特质(Formatting Traits)
std::fmt 通过特质定义不同类型的格式化逻辑,自定义类型需实现对应特质才能被宏处理。核心特质及用法如下:
3.1 核心特质对照表
| 特质名称 | 格式化标记 | 功能描述 | 适用场景 | 标准库实现类型举例 |
|---|---|---|---|---|
Display |
{} |
定义用户友好型格式化(面向最终用户,无冗余信息) | 普通文本显示、用户交互输出 |
String、i32、f64
|
Debug |
{:?} |
定义调试型格式化(面向开发者,包含类型内部结构) | 调试日志、错误排查 | 所有可 derive(Debug) 的类型 |
Binary |
{:b} |
以二进制格式显示整数 | 底层二进制数据展示 |
u8、i32、usize
|
Octal |
{:o} |
以八进制格式显示整数 | Unix 文件权限、底层数据 | 整数类型 |
LowerHex |
{:x} |
以小写十六进制格式显示整数 | 内存地址、哈希值展示 | 整数类型、&[u8]
|
UpperHex |
{:X} |
以大写十六进制格式显示整数 | 硬件寄存器、协议数据展示 | 整数类型 |
Pointer |
{:p} |
以指针地址格式显示(仅支持裸指针 *const T/*mut T) |
内存调试、unsafe 代码排查 | 裸指针类型 |
LowerExp |
{:e} |
以小写科学计数法显示浮点数 | 科学计算、极小/极大数展示 |
f32、f64
|
UpperExp |
{:E} |
以大写科学计数法显示浮点数 | 工程计算、标准化数据输出 |
f32、f64
|
3.2 特质实现方式
方式 1:自动派生(推荐用于 Debug)
通过 #[derive(Debug)] 为自定义类型(结构体、枚举)自动生成 Debug 实现,无需手动编写代码:
#[derive(Debug)] // 自动生成 Debug 特质实现
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 3, y: 4 };
println!("{:?}", p); // 输出:Point { x: 3, y: 4 }
}
方式 2:手动实现(用于自定义 Display 等)
为类型手动实现 Display 等特质,完全控制格式化逻辑:
use std::fmt;
struct Circle {
radius: f64,
}
// 手动实现 Display 特质,自定义圆形的显示格式
impl fmt::Display for Circle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// 使用 write! 宏将内容写入 Formatter
write!(f, "Circle(radius: {:.2})", self.radius)
}
}
fn main() {
let c = Circle { radius: 2.5 };
println!("{}", c); // 输出:Circle(radius: 2.50)
}
4. 格式化语法与控制选项
在格式化标记(如 {})中,可通过 : 后添加参数控制输出格式,常用选项如下:
4.1 基础控制选项
| 语法示例 | 功能描述 | 适用类型 | 输出结果 |
|---|---|---|---|
{:width} |
指定输出最小宽度(不足时用空格填充) | 所有类型 |
format!("{:5}", "hi") → " hi"
|
{:>width} |
右对齐(默认左对齐) | 所有类型 |
format!("{:>5}", "hi") → " hi"
|
{:<width} |
左对齐 | 所有类型 |
format!("{:<5}", "hi") → "hi "
|
{:^width} |
居中对齐 | 所有类型 |
format!("{:^5}", "hi") → " hi "
|
{:fill>width} |
自定义填充字符(需配合对齐符号) | 所有类型 |
format!("{:-^5}", "hi") → "--hi-"
|
{:.precision} |
控制精度:字符串截断长度 / 浮点数小数位数 | 字符串、浮点数 |
format!("{:.2}", 3.1415) → "3.14"
|
{:0width} |
数值专用填充(用 0 填充宽度,符号后补 0) | 整数、浮点数 |
format!("{:06}", -42) → "-00042"
|
{:+} |
数值强制显示符号(正数带 +,负数带 -) |
整数、浮点数 |
format!("{:+}", 42) → "+42"
|
{:#?} |
Debug 格式化带换行与缩进(美观打印) |
实现 Debug 的类型 |
format!("{:#?}", vec![1,2]) → "[\n 1,\n 2\n]"
|
{:#x} |
十六进制带前缀(0x) |
整数 |
format!("{:#x}", 255) → "0xff"
|
4.2 进阶用法:参数引用
通过 $ 引用其他参数作为宽度/精度,或使用命名参数:
// 1. 用位置参数指定宽度
format!("{:1$}", "hi", 5); // 第二个参数(索引 1)作为宽度 → " hi"
// 2. 用命名参数指定精度
format!("{:.prec$}", 3.1415, prec=2); // 命名参数 prec 作为精度 → "3.14"
// 3. 混合命名与位置参数
let name = "Rust";
format!("Hello {name}, score: {0:.2}", 95.567); // 命名参数 + 位置参数 → "Hello Rust, score: 95.57"
5. 关键结构体与类型
5.1 fmt::Formatter
格式化过程的“工具类”,提供以下核心能力:
- 写入内容:
write_str(&str)直接写入字符串,write_fmt(Arguments)写入格式化内容; - 获取格式参数:
width()获取宽度,precision()获取精度,align()获取对齐方式; - 辅助方法:
pad()填充字符,pad_integral()处理数值填充。
示例:
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// 获取精度,默认 2
let prec = f.precision().unwrap_or(2);
// 写入格式化内容
write!(f, "Point(x: {:.prec$}, y: {:.prec$})", self.x, self.y, prec=prec)
}
}
5.2 fmt::Arguments
由 format_args! 宏生成的“预编译格式化对象”,包含格式字符串与参数引用,特点是无堆分配,适合高性能场景(如日志库):
use std::fmt;
// 自定义日志函数,接收 fmt::Arguments
fn log(args: fmt::Arguments<'_>) {
eprintln!("Log: {}", args);
}
fn main() {
let num = 42;
// 生成 Arguments 对象,无堆分配
let args = format_args!("Value: {}", num);
log(args); // 输出:Log: Value: 42
}
5.3 fmt::Result
所有格式化方法的返回类型,定义为 type Result = std::result::Result<(), Error>。其中 fmt::Error 是格式化错误类型(通常仅表示写入失败,实际开发中极少需要处理)。
6. 注意事项
-
类型安全:格式化宏在编译时校验参数类型与格式标记的匹配性,避免运行时错误(如用
{}格式化未实现Display的类型会编译失败); -
无本地化:
std::fmt不支持系统本地化(如小数点分隔符始终为.,不受系统语言影响); -
转义
{与}:若需在格式字符串中显示{或},需用{{或}}转义:format!("Hello {{}}"); // 输出:"Hello {}"
7. 常用场景示例
场景 1:自定义类型调试输出
#[derive(Debug)]
struct User {
id: u64,
name: String,
email: Option<String>,
}
fn main() {
let user = User {
id: 1,
name: "Alice".to_string(),
email: Some("alice@example.***".to_string()),
};
println!("User details: {:#?}", user); // 美观打印 Debug 信息
}
场景 2:错误信息输出到 stderr
use std::fs::read_to_string;
fn read_config(path: &str) -> Result<String, String> {
read_to_string(path).map_err(|e| {
// 用 eprintln! 输出错误到 stderr
eprintln!("Failed to read config: {}", e);
e.to_string()
})
}
场景 3:格式化写入文件
use std::fs::File;
use std::io::Write;
fn write_log(file: &mut File, message: &str) -> std::io::Result<()> {
// 用 writeln! 格式化写入文件
writeln!(file, "[LOG] {}", message)
}