将格式化后的数据写入到一个缓冲区(buffer),而不是直接打印到标准输出或文件中。
这个缓冲区可以是字符串,也可以是需要写入的文件的缓冲区。
write!(writer, format_string, expr1, expr2, ...);
writer 参数是一个实现了 std::io::Write trait 的对象,表示要将数据写入到哪里。
format_string 是一个格式化字符串,可以包含占位符 {},表示后面要插入的值。 expr1、expr2 等是值的表达式,可以是变量,常量,函数等。
write! 宏不会自动添加末尾的换行符。如果需要在写入缓冲区后添加换行符,可以在格式化字符串末尾添加 “\n”。
use std::io::Write;
fn main() {
let mut buffer = Vec::new(); // 创建一个空的缓冲区
let n = 123;
// 使用 write! 宏将格式化字符串 n = {}\n 写入到一个空的缓冲区 buffer 中
// 使用 unwrap() 方法处理写入缓冲区时可能出现的错误
write!(&mut buffer, "n = {}\n", n).unwrap();
// 使用 String::from_utf8_lossy() 方法将缓冲区的内容转换为字符串格式,并进行输出
println!("{}", String::from_utf8_lossy(&buffer));
}
// 打印内容
// n = 123
// \n
write! 宏的返回值是一个 std::io::Result<()> 类型的值,表示写入操作是否成功。
use std::io::Write;
fn main() {
// 创建一个缓冲区
let mut buffer = Vec::new();
let n = 123;
// 调用 write! 宏写入数据
let result = write!(&mut buffer, "n = {}\n", n);
if result.is_err() {
// unwrap_err 只能在err的时候使用
println!("Error: {}", result.unwrap_err());
} else {
println!("Write succeed.");
println!("{:?}", buffer);
}
}
// 打印
// Write succeed.
// [110, 32, 61, 32, 49, 50, 51, 10]
use std::fmt; // 导入 `fmt` 模块。
// 定义一个包含单个 `Vec` 的结构体 `List`。
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// 使用元组的下标获取值,并创建一个 `vec` 的引用
// 创建一个指向结构体 List 中第一个元素的不可变引用
// self 是一个 &List 类型的引用,它表示一个指向类型为 List 的结构体实例的引用
// .0 表示取得 List 结构体中的第一个元素
// 必须使用 &self.0 来获取 List 这个引用所指向的 Vec 实例
let vec = &self.0;
// ? 运算符,表示在发生错误时返回错误信息
// 这样在上层函数中可以进行进一步的处理
// ? 运算符只有在当前函数返回 Result 类型时才能使用
write!(f, "[")?;
// 使用 `v` 对 `vec` 进行迭代,并用 `count` 记录迭代次数。
for (count, v) in vec.iter().enumerate() {
// 对每个元素(第一个元素除外)加上逗号。
// 使用 `?` 或 `try!` 来返回错误。
if count != 0 { write!(f, ", ")?; }
write!(f, "{}", v)?;
}
// 加上配对中括号,并返回一个 fmt::Result 值
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
println!("{}", v);
}
use std::fmt; // 导入 `fmt` 模块。
// 定义一个包含单个 `Vec` 的结构体 `List`。
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// 使用元组的下标获取值,并创建一个 `vec` 的引用
// 创建一个指向结构体 List 中第一个元素的不可变引用
// self 是一个 &List 类型的引用,它表示一个指向类型为 List 的结构体实例的引用
// .0 表示取得 List 结构体中的第一个元素
// 必须使用 &self.0 来获取 List 这个引用所指向的 Vec 实例
let vec = &self.0;
// ? 运算符,表示在发生错误时返回错误信息
// 这样在上层函数中可以进行进一步的处理
// ? 运算符只有在当前函数返回 Result 类型时才能使用
write!(f, "[")?;
// 使用 `v` 对 `vec` 进行迭代,并用 `count` 记录迭代次数。
for (count, v) in vec.iter().enumerate() {
// 对每个元素(第一个元素除外)加上逗号。
// 使用 `?` 或 `try!` 来返回错误。
if count != 0 { write!(f, ", ")?; }
write!(f, "{}: {}", count, v)?;
}
// 加上配对中括号,并返回一个 fmt::Result 值
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
println!("{}", v);
}
对于 Vec 或其他任意泛型容器(generic container)
fmt::Display 都没有实现。因此在这些泛型的情况下要用 fmt::Debug。
use std::fmt; // 导入 `fmt`
// 带有两个数字的结构体
// 推导出 `Debug`,以便与 `Display` 的输出进行比较
#[derive(Debug)]
struct MinMax(i64, i64);
// 实现 `MinMax` 的 `Display`。
impl fmt::Display for MinMax {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// 使用 `self.number` 来表示各个数据。
write!(f, "({}, {})", self.0, self.1)
}
}
// 为了比较,定义一个含有具名字段的结构体
#[derive(Debug)]
struct Point2D {
x: f64,
y: f64,
}
// 类似地对 `Point2D` 实现 `Display`
impl fmt::Display for Point2D {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// 自定义格式,使得仅显示 `x` 和 `y` 的值。
write!(f, "x: {}, y: {}", self.x, self.y)
}
}
fn main() {
let minmax = MinMax(0, 14);
println!("Compare structures:");
println!("Display: {}", minmax);
println!("Debug: {:?}", minmax);
let big_range = MinMax(-300, 300);
let small_range = MinMax(-3, 3);
println!("The big range is {big} and the small range is {small}", small = small_range, big = big_range);
let point = Point2D { x: 3.3, y: 7.2 };
println!("Compare points:");
println!("Display: {}", point);
println!("Debug: {:?}", point);
// 报错。`Debug` 和 `Display` 都被实现了,但 `{:b}` 需要 `fmt::Binary`
// 得到实现。这语句不能运行。
// println!("What does Point2D look like in binary: {:b}?", point);
}