简介
在本实验中,将讲解 Rust 中的格式化打印功能。std::fmt 模块提供了诸如 format!、print!、println!、eprint! 和 eprintln! 等宏,用于处理打印任务。这些宏允许使用占位符格式化文本,占位符会被相应的参数替换。可以使用位置参数和命名参数,并使用格式字符应用不同的格式。这些宏还支持文本对齐、数字填充以及设置十进制数的精度。fmt::Display 特性用于以用户友好的方式格式化文本,而 fmt::Debug 特性用于调试目的。Rust 还在编译时检查格式化的正确性。此外,文中提到实现 fmt::Display 特性会自动实现 ToString 特性,自定义类型需要实现 fmt::Display 特性才能进行打印。本实验还包括练习使用格式化打印宏和特性的活动。
注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用
main.rs,并通过rustc main.rs &&./main进行编译和运行。
格式化打印
打印操作由 std::fmt 中定义的一系列 宏 处理,其中一些包括:
format!:将格式化后的文本写入String。print!:与format!相同,但文本会打印到控制台(io::stdout)。println!:与print!相同,但会追加一个换行符。eprint!:与print!相同,但文本会打印到标准错误输出(io::stderr)。eprintln!:与eprint!相同,但会追加一个换行符。
所有这些宏都以相同的方式解析文本。另外,Rust 在编译时会检查格式化的正确性。
fn main() {
// 一般来说,`{}` 会自动被任何参数替换。这些参数会被字符串化。
println!("{} 天", 31);
// 可以使用位置参数。在 `{}` 内指定一个整数,决定将替换哪个额外的参数。参数从格式字符串后的 0 开始。
println!("{0}, 这是 {1}。{1}, 这是 {0}", "爱丽丝", "鲍勃");
// 也可以使用命名参数。
println!("{subject} {verb} {object}",
object="那只懒狗",
subject="那只敏捷的棕色狐狸",
verb="跳过");
// 通过在 `:` 后指定格式字符,可以调用不同的格式化方式。
println!("十进制: {}", 69420); // 69420
println!("二进制: {:b}", 69420); // 10000111100101100
println!("八进制: {:o}", 69420); // 207454
println!("十六进制: {:x}", 69420); // 10f2c
println!("十六进制: {:X}", 69420); // 10F2C
// 可以使用指定的宽度对文本进行右对齐。这将输出 " 1"。(四个空格和一个 "1",总宽度为 5。)
println!("{number:>5}", number=1);
// 可以用额外的零填充数字,
println!("{number:0>5}", number=1); // 00001
// 通过翻转符号进行左对齐。这将输出 "10000"。
println!("{number:0<5}", number=1); // 10000
// 可以通过在格式说明符后追加 `$` 来在格式说明符中使用命名参数。
println!("{number:0>width$}", number=1, width=5);
// Rust 甚至会检查以确保使用了正确数量的参数。
println!("我的名字是 {0}, {1} {0}", "邦德");
// FIXME ^ 添加缺失的参数:"詹姆斯"
// 只有实现了 `fmt::Display` 的类型才能用 `{}` 进行格式化。用户定义的类型默认不实现 `fmt::Display`。
#[allow(dead_code)] // 禁用 `dead_code`,它会警告未使用的模块
struct Structure(i32);
// 这将无法编译,因为 `Structure` 没有实现 `fmt::Display`。
// println!("这个结构体 `{}` 不会打印...", Structure(3));
// TODO ^ 尝试取消注释这一行
// 对于 Rust 1.58 及以上版本,可以直接从周围的变量捕获参数。就像上面一样,这将输出
// " 1",四个空格和一个 "1"。
let number: f64 = 1.0;
let width: usize = 5;
println!("{number:>width$}");
}
std::fmt 包含许多用于控制文本显示的 特性。下面列出了两个重要特性的基本形式:
fmt::Debug:使用{:?}标记。用于格式化文本以进行调试。fmt::Display:使用{}标记。以更优雅、用户友好的方式格式化文本。
在这里,我们使用了 fmt::Display,因为标准库为这些类型提供了实现。要打印自定义类型的文本,还需要更多步骤。
实现 fmt::Display 特性会自动实现 ToString 特性,这使我们能够将类型转换为 String。
在第 43 行,#[allow(dead_code)] 是一个 [属性],仅应用于它后面的模块。
活动
- 修复上述代码中的问题(见 FIXME),使其能够无错误运行。
- 尝试取消注释尝试格式化
Structure结构体的那一行(见 TODO) - 添加一个
println!宏调用,通过控制显示的小数位数来打印:Pi 约为 3.142。在本练习中,使用let pi = 3.141592作为 pi 的近似值。(提示:你可能需要查看std::fmt文档以设置要显示的小数位数)
总结
恭喜你!你已经完成了格式化打印实验。你可以在 LabEx 中练习更多实验来提升你的技能。