此 EEP 提議新的字串插值語法,允許將表達式嵌入到字串常數中,以使建構複合字串更具可讀性。
例如,新語法
bf"A utf-8 binary string: ~2 + 2~"
會計算為
<<"A utf-8 binary string: 4"/utf8>>
此提案在兩個軸上添加了四種類型的字串插值(utf-8 二進制或 unicode 碼位列表,以及面向用戶或面向開發人員的格式)。
結果是有四種帶有插值值的通用語法類別
% binary format
<<"A utf-8 binary string: 4"/utf8>> =
bf"A utf-8 binary string: ~2 + 2~"
% list format
"A unicode codepoint list string: 4" =
lf"A unicode codepoint list string: ~2 + 2~"
% binary debug
<<"A utf-8 binary string: {4, foo, [x, y, z]}"/utf8>> =
bd"A utf-8 binary string: ~{2 + 2, foo, [x, y, z]}~"
% list debug
"A unicode codepoint list string: {4, foo, [x, y, z]}" =
ld"A unicode codepoint list string: ~{2 + 2, foo, [x, y, z]}~"
任意表達式可以嵌套在字串插值替換中,包括變數、函數呼叫、巨集,甚至進一步的字串插值表達式。
在 stdlib 中的 string
模組中,字串由 unicode:chardata()
表示,也就是碼位列表、帶有 UTF-8 編碼碼位的二進制(UTF-8 二進制)或兩者的混合。
考慮到這一點,面向列表和面向二進制的字串插值語法接受任何類型的插值值,但是插值的使用者會決定他們想要基於他們使用的插值類型來生成 unicode:char_list()
或 unicode:unicode_binary()
(bf"..."
和 bd"..."
來建立二進制,或 lf"..."
和 ld"..."
來建立列表)。
列表字串對於向後相容性和便利性最有用。二進制字串對於記憶體緊湊性和 IO 最有用。
開發人員通常有兩種相似但不同的情況需要格式化字串:當記錄/除錯時,以及當向用戶顯示數據時。
在記錄或除錯時,最重要的功能通常是能夠列印任何類型的術語,並且它應該無損地往返並且被開發人員明確地讀取。這些屬性的例子包括保留執行時類型資訊,例如在格式化字串時保持字串引用,並以完整的範圍和解析度列印浮點數。
當顯示給用戶時,最重要的功能通常是它們始終是人類可讀的且格式整潔。這些屬性的例子包括逐字格式化字串,不帶引號,並且不保留任何 Erlang 式的符號(例如,我們不想列印 Erlang 元組,因為它們對一般應用程式使用者沒有多大意義),因此我們寧願得到一個 badarg
錯誤來迫使開發人員做出明確的格式化決策。
讓我們考慮一下先前介紹的兩個用例
bd"~Timestamp~: ~Query~ returned ~Result~"
bf"您的帳戶餘額現在是 ~my_app:format_balance(Currency, Balance)~"
。值得注意的是,此處的設計和實作並未排除未來引入格式化選項,例如 bf"float: ~.2f(MyFloat)~"
,就像使用 io_lib:format
等一樣。但是現有的 stdlib 函數可以提供類似的功能,例如 bf"float: ~float_to_binary(MyFloat, [{decimals, 2}, compact])~"
,並且可以分解為它們自己的可重用函數。
Elixir 使用 #{...}
在字串中引入插值表達式,並且重複使用該語法可能很方便。不幸的是,這與 Erlang 的 Map 語法衝突。Elixir 的 Map 使用 %{...}
,因此它沒有該衝突。
為了解析插值字串,掃描器會追蹤一些關於我們目前是否在插值字串中的額外狀態,此時它會啟用對 ~
作為插值表達式的分隔符號的識別,並生成新的 Token 來表示插值字串的各種組件。
在編譯和 Shell 評估的早期階段,插值字串被 desugar 成對 io_lib
模組中函數的呼叫,因此不會影響編譯或評估的後續階段。
PR #7343
新的字串插值語法以前不是有效的語法,因此支援新語法的工具應該與現有的原始碼完全向後相容。
新語法將在標準庫中生成對新的二進制建構函數的呼叫,因此使用此新功能編譯的 BEAM 檔案將與較早的版本不相容。
本文件置於公共領域或 CC0-1.0-Universal 許可證之下,以較寬鬆者為準。