并不是所有 x
中的 #
都需要双写。直接用 primitive 实现的一般不需要双写。但是即使这样也有例外情况,这应该是 LaTeX3 的函数命名不一致导致的,由于 \cs_new:Npx
这些函数使用广泛,目前看来不太可能再修改它们的名称了。目前我记得的不需要双写的 #
的 x
参数有 \cs_new...
和 \cs_(g)set...
系列以及 \iow_shipout_x:Nn
。所有的 \exp_..
中的 x
都需要双写(包括 \cs_generate_variant:Nn
和 \prg_generate_conditional_variant:Nnn
生成的变体)。
需要双写的原因是定义了一个临时的宏,见后文。
当 #
作为引用参数的标识时,它应该仅写一次(随嵌套次数而倍增),当 #
作为它自己时,应该双写。
需要双写的 #
可以使用 \exp_not:n
包裹起来,这样就不要双写。如可以 \use:x { \exp_not:n { \def\tmp#1{#1} } }
。
\cs_new:Npx
相当于 \long\edef
。这里的 x 其实是 e。
定义函数时,\edef\test#1#2{#1,#2}
,括号里的 #1
#2
是引用第一、二个参数,应该把它们看成一个整体作为 1 个记号,##
也应当看成一个记号。\test
实际上是:两个参数的宏,它展开为 <参数1>,<参数2>
。\edef\test#1{\def\noexpand\foo##1#1##2{##1 ##2 #1 \def\foo####1{####1##2}}}
,\test
是有一个参数的宏,它展开为 \def\foo#1<参数1>#2{#1 #2 <参数1> \def\foo##1{##1#2}}
。
而 \use:x
实际上是 \def\use:x#1{\edef\temp{#1}\temp}
,当写 \use:x{?#1?}
时,\use:x
展开为 \edef\temp{?#1?}\temp
,此时在定义 \temp
时就会出错,因为它没有参数,但它的替换文本中却引用了参数,所以必须双写 \use:x{?##1?}
,此时 ##
表示 #
,而不是引用参数的标识。
而 \use:e
则不是这样,它使用 \expanded
primitive 实现,没有定义一个临时的宏,#
直接就是作为它自己。
还是那句话,能使用 e
就使用 e
而非 x
。
问 l3中宏展开部分对x型参数中双写#的疑问