rust格式化打印

rust格式化打印

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 {} 定义用户友好型格式化(面向最终用户,无冗余信息) 普通文本显示、用户交互输出 Stringi32f64
Debug {:?} 定义调试型格式化(面向开发者,包含类型内部结构) 调试日志、错误排查 所有可 derive(Debug) 的类型
Binary {:b} 以二进制格式显示整数 底层二进制数据展示 u8i32usize
Octal {:o} 以八进制格式显示整数 Unix 文件权限、底层数据 整数类型
LowerHex {:x} 以小写十六进制格式显示整数 内存地址、哈希值展示 整数类型、&[u8]
UpperHex {:X} 以大写十六进制格式显示整数 硬件寄存器、协议数据展示 整数类型
Pointer {:p} 以指针地址格式显示(仅支持裸指针 *const T/*mut T 内存调试、unsafe 代码排查 裸指针类型
LowerExp {:e} 以小写科学计数法显示浮点数 科学计算、极小/极大数展示 f32f64
UpperExp {:E} 以大写科学计数法显示浮点数 工程计算、标准化数据输出 f32f64

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. 注意事项

  1. 类型安全:格式化宏在编译时校验参数类型与格式标记的匹配性,避免运行时错误(如用 {} 格式化未实现 Display 的类型会编译失败);
  2. 无本地化std::fmt 不支持系统本地化(如小数点分隔符始终为 .,不受系统语言影响);
  3. 转义 {}:若需在格式字符串中显示 {},需用 {{}} 转义:
    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)
}

转载请说明出处内容投诉
CSS教程网 » rust格式化打印

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买