本 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]}~"
任意表达式都可以嵌套在字符串插值替换中,包括变量、函数调用、宏,甚至进一步的字符串插值表达式。
在标准库的 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"You account balance is now ~my_app:format_balance(Currency, Balance)~"
。值得注意的是,此设计和实现中的任何内容都不会阻止未来引入诸如 bf"float: ~.2f(MyFloat)~"
之类的格式化选项,就像使用 io_lib:format
等一样。但是,现有的标准库函数可以提供类似的功能,例如 bf"float: ~float_to_binary(MyFloat, [{decimals, 2}, compact])~"
,并且可以分解为它们自己的可重用函数。
Elixir 使用 #{...}
在字符串中引入插值表达式,并且重用该语法可能很方便。不幸的是,这与 Erlang 的 Map 语法冲突。Elixir 的 Map 使用 %{...}
,因此它没有该冲突。
要解析插值字符串,扫描器会跟踪一些关于我们当前是否在插值字符串中的额外状态,此时它会启用对 ~
作为插值表达式分隔符的识别,并生成新的标记,这些标记表示插值字符串的各种组件。
在编译和 Shell 求值的早期,插值字符串被转换为对 io_lib
模块中函数的调用,因此不会影响编译或求值的后续阶段。
PR #7343
新的字符串插值语法以前不是有效的语法,因此支持新语法的工具应该完全向后兼容现有源代码。
新语法将生成对标准库中新的二进制构造函数的调用,因此使用此新特性编译的 BEAM 文件将与早期版本不兼容。
本文档置于公共领域或 CC0-1.0-Universal 许可之下,以更宽松者为准。