查看 l3prop 的实现代码,我对以下部分(在 \prop_remove:Nn 的定义中)感到困惑:
\cs_new_protected:Npn \__prop_split:NnTF #1#2
{ \exp_args:NNo \__prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } }
\cs_new_protected:Npn \__prop_split_aux:NnTF #1#2#3#4
{
\cs_set:Npn \__prop_split_aux:w ##1
\__prop_pair:wn #2 \s__prop ##2 ##3 \s__prop_mark ##4 ##5 \s__prop_stop
{ ##4 {#3} {#4} }
\exp_after:wN \__prop_split_aux:w #1 \s__prop_mark \use_i:nn
\__prop_pair:wn #2 \s__prop { } \s__prop_mark \use_ii:nn \s__prop_stop
}
\cs_new:Npn \__prop_split_aux:w { }
\cs_new_protected:Npn \prop_remove:Nn #1#2
{
\__prop_split:NnTF #1 {#2}
{ \tl_set:Nn #1 { ##1 ##3 } }
{ }
}
我对 \__prop_split:NnTF 的定义感到困惑......更确切地说,我的解释(从代码,而不是函数签名)它是一个只有两个参数 #1 #2 的宏(尽管签名建议有 4 个参数(TF 部分))。
更重要的是使用/定义 \__prop_split_aux:NnTF,它被定义为一个具有 4 个参数的宏,但是使用时(在 \__prop_split:NnTF 中)只给出两个参数......
这是怎么回事?(或者我遗漏了哪些定义?)
谢谢你的帮助。
编辑:不要忘记 \__prop_split_aux:w 的奇怪(对我来说)定义,我的意思是,从 \cs_set:Npn 的签名来看,我期望一个 csname (\__prop_split_aux:w) 一个参数“列表”(##1),然后是“代码”本身(平衡),但我看到的却(?!)只是一个标记(\__prop_pair:wn)
答案1
每次 TeX 解析参数时,它都需要一点时间,如果它不必要地拾取参数,它就会需要一点不必要的额外时间。因此,时间紧迫的应用程序会避免这种情况(如果不需要的话)(这是一种常用技术,并不特定于 L3 编程层)。
\__prop_split:NnTF
直接选取 2 个参数并处理它们。作为其最终操作,它调用为其提供 2 个参数。由于该命令需要 4 个参数,因此它从输入流中获取缺少的 2 个 (TF)。这与选取 4 个参数并像这样结束的\__prop_split_aux:NnTF
情况相同:\__prop_split:NnTF
\cs_new_protected:Npn \__prop_split:NnTF #1#2#3#4
{ \exp_args:NNo \__prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } {#3} {#4} }
速度较慢的原因在于,一个命令可能很长#3
,#4
现在需要读取两次并传递。对于在文档中调用数千次的命令,即使在快速机器上,随着时间的推移,这些命令也会累积起来。
我同意下面@egreg的评论!以上是对您所展示的代码中发生的事情的解释,而不是建议您在自己的代码中使用它。进行这些优化意味着为了获得最小的速度改进而降低代码的可读性。这只在少数地方是合理的(内核的部分符合条件,但软件包或用户代码很少符合条件)。这是内核代码不一定是学习如何在高级代码中使用 L3 程序层的最佳场所的原因之一。