假期,我尝试使用rust做一款命令行工具,来磨砺自己的rust技术熟练度。起初,面对各式各样的字符串格式化功能点,我傻乎乎地尝试自己造轮子。但,实在是遇到了太多技术难点(可难死我了)。后来,通过在论坛发贴请教,我才了解到【标准库 - format!语法扩展】已经90%地满足了我的需求。至于,剩余10%的功能,可通过实现不同的format trait来深度定制-达成。
于是,我修改了假期目标为:
重新复习format!宏相关知识点。相比于之前(真是学过N遍了),我要提高对这块知识点的重视程度。在复习过程,做些归纳总结和条理清晰的笔记。
基于【标准库 - format!语法扩展】与【实现format trait深度定制】的手段,来做一款rust命令行工具。而不是,自己重新造轮子。
下面即是我对第一个目标的达成成果(除了丰富的教条总结归纳,还有30个例程) --- 掌握rust,先做“教条侠”。第二个目标还在进行中...

format!("以{parameter}为占位符的·格式化字符串·字面量", arguments...){parameter}名曰Formatting Argumentargument名曰Value ArgumentFormatting Argument格式下文中的 [...]结构表示
一对 [与]之间的内容是可有可无的。而且 [...]结构是可多层嵌套的。
{[argument][:format-spec]}argument:【引用指令】表示如何找到Value Argumentformat-spec:【格式化指令】表示如何格式化Value Argument为字符串。Formatting argument -> argument以如下三种形式引用Value Argument{} 名曰:Next (Value) ArgumentValue Arguments的影响,因为前者维护了独立的【游标变量】来跟踪迭代位置。[例程1](Value) Argument,逐一遍历arguments列表中的每一项。但是,当format-spec内包含.*时,则会一次迭代遍历两项(下文有详细描述)。{positional parameter} 名曰:【索引】(Value) Argumentpositional parameter是integer值。0的索引值,随机访问(Value) Argument。{naming parameter} 名曰:【具名】(Value) Argument [例程2]Value Arguments列表的末端;格式:<parameter name>=<value>。Value Arguments列表中。相反,编译器会naming parameter是identifier字符串。(Value) Argument。Formatting argument -> format-spec以如下五种形式进一步格式化Value Argument下文中的 [...]结构表示
一对 [与]之间的内容是可有可无的。而且 [...]结构是可多层嵌套的。
若 mini-width与max-length同时指定,并且mini-width大于max-length,那么 [例程8]
std::fmt::Display::to_string()成员方法将Value Argument序列化为字符串。

padding-char名曰:“填充”align名曰:“对齐”若对齐未生效(比如,对 Debug trait实例),那就
mini-width名曰:“最小宽度”max-length名曰:最多显示字符数(从左向右截取)[例程6]< 左 (默认)^ 中> 右Value argument值$后缀【索引值】引用某个Value argument值 [例程4]$后缀【具名变量】引用 [例程5]Value argument值Value argument代表最多显示字符数Value argument值$后缀【索引值】引用某个Value argument值$后缀【具名变量】引用.*表示当前Formatting argument同时关联了两个Value argument [例程7]{[<integer | identifier>][:[[[<padding-char>]<align>]<mini-width>][.<max-length>]]} [例程3]max-length截断字符串mini-width对截断后的字符串有填充与对齐处理Value argument,就数字格式化而言,【正负号】与【进制符】都被计入总宽度内,并挤占了【占位符】的“坑位”。[例程16]
std::fmt::Display::to_string()成员方法将Value Argument序列化为字符串。

padding-char名曰:填充align名曰:对齐若对齐未生效(比如,对 Debug trait实例),那就
sign名曰:正负号0名曰:填充0数字mini-width名曰:最小宽度precision名曰:精度 [例程14]padding-char指定整个数字(含正负号)前后的填充符。padding-char填充符可以是任意字符。padding-char的填充优先级低于0 [例程10]sign后的0填充符作用不同,< 左^ 中> 右 (默认)-号+。即,总是显示+/-号0表示在【正负号】与【有效数字】之间以数字0加以填充`。00填充优先级高于padding-char [例程11]padding-char填充符作用不同,Value argument值$后缀【索引值】引用某个Value argument值 [例程12]$后缀【具名变量】引用 [例程13]Value argumentValue argument代表精度Value argument值$后缀【索引值】引用某个Value argument值$后缀【具名变量】引用.*表示当前Formatting argument同时关联了两个Value argument [例程15]{[<integer | identifier>][:[[[<padding-char>]<align>][<sign>][0]<mini-width>][.<precision>]]} [例程9]Value argument,就数字格式化而言,【正负号】与【进制符】都被计入总宽度内,并挤占了【占位符】的“坑位”。[例程22]
任何实现了 Format trait的【自定义-数据类型】的实例都能被format-spec指令序列化与格式化。
标准库已经为基本数据类型提供了 Format trait的默认实现。

padding-char名曰:填充align名曰:对齐若对齐未生效(比如,对 Debug trait实例),那就
sign名曰:正负号#名曰:进制换算指令。0名曰:填充0数字mini-width名曰:最小宽度numeration名曰:进制符
padding-char指定整个数字(含·正负号·与·进制符前缀0x, 0o, 0b·)前后的填充符。padding-char填充符可以是任意字符。padding-char的填充优先级低于#0 [例程18]#后0填充符的作用不同,< 左^ 中> 右 (默认)-号+。即,总是显示正负号。numeration参数配套出现。#0表示在【进制符前缀0x, 0o, 0b】与【有效数字】之间以数字0加以填充`。0#0填充优先级高于padding-char [例程19]padding-char填充符作用不同,Value argument值$后缀【索引值】引用某个Value argument值 [例程20]$后缀【具名变量】引用 [例程21]{[<integer | identifier>][:[[<padding-char>]<align>][<sign>]#[[0]<mini-width>]<numeration>]} [例程17]Value argument,
就数字格式化而言,【正负号】与【进制符】都被计入总宽度内,并挤占了【占位符】的“坑位”。[例程27]
任何实现了 Format trait的【自定义-数据类型】的实例都能被format-spec指令序列化与格式化。
标准库已经为基本数据类型提供了 Format trait的默认实现。
padding-char名曰:填充align名曰:对齐若对齐未生效(比如,对 Debug trait实例),那就
sign名曰:正负号0名曰:填充0数字mini-width名曰:最小宽度numeration名曰:进制符
padding-char指定整个数字(含正负号)前后的填充符。padding-char填充符可以是任意字符。padding-char的填充优先级低于0 [例程23]sign后0填充符作用不同,< 左^ 中> 右 (默认)-号+。即,总是显示正负号0表示在【正负号】与【有效数字】之间以数字0加以填充。00填充优先级高于padding-char [例程24]padding-char填充符作用不同,Value argument值$后缀【索引值】引用某个Value argument值 [例程25]$后缀【具名变量】引用 [例程26]{[<integer | identifier>][:[[[<padding-char>]<align>][<sign>][[0]<mini-width>]]<numeration>]}Value argument,Vec<T>和HashMap<K, V>。{[<integer | identifier>][:#?]} [例程28]{与}字面量
{为{{}为}}Value argument两种语法错误形式
Value argument未被任何Formatting Argument所引用(Value) Argument或Next (Value) Argument出现于【具名】(Value) Argument之后。[例程29]format-spec格式化指令对自定义数据类型(的实例)起作用
Format trait,从std::fmt::Display与std::fmt::Debug到std::fmt::Octal等等一个都别落下。[例程30]Format trait默认实现已经帮助开发者完成了开发者仅需调用 std::fmt::Formatter的成员方法(比如,std::fmt::Formatter::fill(&self))就可获取格式化指令的具体值。
format-spec指令值的提取工作fn fmt(...) -> std::fmt::Result的返回值类型是Result,但是fn fmt()不应该将format trait业务实现代码的“本地”错误伪装成std::fmt::Result返回。因为rust设计要求:std::fmt::Result仅被用来反映底层输出流遇到的硬件失败。std::fmt::Display与std::fmt::Debug的区别trait都差不多。它们之间的差别之处都集中在语义上:std::fmt::Display表示一个类型实例能够由UTF-8字符串来描述。因为不是所有类型的实例都是可字符串描述的(只可意会,不可言传),所以不是所有的类型都需要实现该trait。std::fmt::Debug用于debugging目的,描述某个类型实例的内部数据状态。所以,理论上,所有的类型都应该实现该trait,以方便随时按需程序调试。
原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。