在命令定义中省略参数

在命令定义中省略参数

有时我会定义模型命令(\foo如下例所示),然后根据该模型定义特定命令(\fool如下例所示)。但是,我并不完全确定我使用的语法是否正确。

\documentclass{minimal}
\usepackage{xparse}
\NewDocumentCommand\foo{mm}{#2#1}
\NewDocumentCommand\fool{}{\foo!}
\NewDocumentCommand\foot{m}{\foo!{#1}}

\begin{document}
   \fool{⟨sth⟩}, \foot{⟨sth⟩}
\end{document}

\fool和 的行为不同吗\foot?一个比另一个好吗?据我了解,和都\fool{⟨sth⟩}扩展\foot{⟨sth⟩}到,\foo!{⟨sth⟩}然后扩展到⟨sth⟩!,这是预期的结果。这样对吗?

答案1

TeX 是一种宏扩展语言。如果我们查看 中的一些随机定义plain.tex,我们会发现一些仅出现发生争论。例如

\def\line{\hbox to\hsize}

应该称为\line{text}。因此,看似 的参数\line实际上是 的参数\hbox to\hsize

\makeboxLaTeX 模型更加复杂。例如,

\DeclareRobustCommand\makebox{%
  \leavevmode
  \@ifnextchar(%)
    \@makepicbox
    {\@ifnextchar[\@makebox\mbox}}%

其中有参数。获取参数将延迟到\@makepicbox\@makebox\mbox,具体取决于后面的标记。

也采用了同样的方法。如果你在定义之后xparse再看一下 的定义,你会看到\foo

> \foo=\protected macro:
->\__xparse_start_expandable:nNNNNn {mm}\foo  \foo  \foo code ?{\__xparse_expandable_grab_m:w \__xparse_expandable_grab_m:w }.

so\foo没有参数(像\makebox)。参数实际上是通过\foo•code(项目符号表示名称中的空格)以相当复杂的方式获取的,因为目的是能够指定强制或可选参数的复杂序列。以下是它的定义:

> \foo code=\protected\long macro:
#1#2->#2#1.

另一方面,如果你这样做

\NewDocumentCommand{\foo}{O{x}m}

那么的定义\foo就是

> \foo=\protected macro:
->\__xparse_start:nNNnnn {O{x}m}\foo  \foo code {\__xparse_grab_D:w []\__xparse_grab_m_1:w }{{\prg_do_nothing: x}\c__xparse_no_value_tl }{}.

\foo•code会和以前一样。

对于\fool和 也类似\foot。两个版本最终都会以相同的方式工作,因为两者都会以

\foo•code ! {(sth)}

在主输入流中。

唯一的区别是第二个参数用 读取两次,\foot用 只读取一次\fool。总的来说,节省的时间并不值得。

使用和朋友时,建议\NewDocumentCommand始终指定完整的参数集。然而,有些情况下使用“简化”版本更简单,但应将其保持在最低限度,以最大限度地提高代码的可读性。

相关内容