[Rust 筆記] format- 宏使用心得 - 彙總
假期,我嘗試使用rust
做一款命令行工具,來磨礪自己的rust
技術熟練度。起初,面對各式各樣的字符串格式化功能點,我傻乎乎地嘗試自己造輪子。但,實在是遇到了太多技術難點(可難死我了)。後來,通過在論壇發貼請教,我才瞭解到【標準庫 - format!
語法擴展】已經90%
地滿足了我的需求。至於,剩餘10%
的功能,可通過實現不同的format trait
來深度定製 - 達成。
於是,我修改了假期目標爲:
-
重新複習
format!
宏相關知識點。相比於之前(真是學過N
遍了),我要提高對這塊知識點的重視程度。在複習過程,做些歸納總結和條理清晰的筆記。 -
基於【標準庫 -
format!
語法擴展】與【實現format trait
深度定製】的手段,來做一款rust
命令行工具。而不是,自己重新造輪子。
下面即是我對第一個目標的達成成果(除了豐富的教條總結歸納,還有30
個例程) --- 掌握rust
,先做 “教條俠”。第二個目標還在進行中...
依賴關係宏觀架構圖
宏調用格式
format!("以{parameter}爲佔位符的·格式化字符串·字面量", arguments...)
-
{parameter}
名曰Formatting Argument
-
argument
名曰Value Argument
Formatting Argument
格式
下文中的
[...]
結構表示
一對
[
與]
之間的內容是可有可無的。而且
[...]
結構是可多層嵌套的。
{[argument][:format-spec]}
-
argument
:【引用指令】表示如何找到Value Argument
-
format-spec
:【格式化指令】表示如何格式化Value Argument
爲字符串。
Formatting argument -> argument
以如下三種形式引用Value Argument
-
{}
名曰:Next (Value) Argument
-
【順序訪問】不會受【隨機訪問】· 跳躍式尋找
Value Arguments
的影響,因爲前者維護了獨立的【遊標變量】來跟蹤迭代位置。[例程 1] -
順序訪問
(Value) Argument
,逐一遍歷arguments
列表中的每一項。但是,當format-spec
內包含.*
時,則會一次迭代遍歷兩項(下文有詳細描述)。 -
Value Argument:無要求
-
{positional parameter}
名曰:【索引】(Value) Argument
-
positional parameter
是integer
值。 -
以始於
0
的索引值,隨機訪問(Value) Argument
。 -
Value Argument:無要求
-
{naming parameter}
名曰:【具名】(Value) Argument
[例程 2] -
要麼,出現於
Value Arguments
列表的末端;格式:<parameter name>=<value>
。 -
要麼,不出現在
Value Arguments
列表中。相反,編譯器會 -
在當前作用域內,
-
尋找同名綁定變量,
-
使用該綁定變量的值。(餒餒地逆天了)
-
naming parameter
是identifier
字符串。 -
經由【參數名】,隨機訪問
(Value) Argument
。 -
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
加以填充 `。 -
填充符號僅能是數字
0
-
0
填充優先級高於padding-char
[例程 11] -
與
padding-char
填充符作用不同, -
某個
Value argument
值 -
或,當前作用域內,某個綁定變量的值
-
要麼,缺省。即,沒有限制。
-
要麼,數字字面量。
-
要麼,
$
後綴【索引值】引用某個Value argument
值 [例程 12] -
要麼,
$
後綴【具名變量】引用 [例程 13] -
被格式化的值是後一個
Value argument
-
而在被格式值前面(左側)的
Value 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
加以填充。 -
填充符號僅能是數字
0
-
0
填充優先級高於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
,以方便隨時按需程序調試。
結束語
這次想和大家分享的內容就是這些。
---------------------
另附上苦瓜小仔的一份思維導圖:
清晰版請參閱:https://www.yuque.com/zhoujiping/programming/pygvaf?inner=sSp4s
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/UtO6FkNAspzZF8HeMWbr7w