命令接收的参数比传递给它的参数多,这样可以吗?

命令接收的参数比传递给它的参数多,这样可以吗?

\foo一个控制序列可以包含另一个控制序列吗?\slurp该控制序列吸收的参数比\foo实际传递给它的参数还多。

例如,这样做可以吗:

\documentclass{article}

\newcommand\foo  [1]{#1 \slurp}    
\newcommand\slurp[3]{#1 #2 #3}

\begin{document}
\foo{a}{b}{c}{d}
\end{document}

而不是这样?

\documentclass{article}

\newcommand\foo  [4]{#1 \slurp{#2}{#3}{#4}}    
\newcommand\slurp[3]{#1 #2 #3}

\begin{document}
\foo{a}{b}{c}{d}
\end{document}

答案1

这样可以吗?当然可以!事实上,这种宏定义有很多用途。最值得注意的是带星号的命令变体的基本定义。例如,article定义\section

\newcommand\section{\@startsection {section}{1}{\z@}%
                                   {-3.5ex \@plus -1ex \@minus -.2ex}%
                                   {2.3ex \@plus.2ex}%
                                   {\normalfont\Large\bfseries}}

了解需要多长时间参数,即使我们通常将其指定/用作\section[<toc>]{<title>}?! 这是因为\@startsection需要 6 个参数,然后进行测试以查看用户是否添加了星号。从latex.ltx

\def\@startsection#1#2#3#4#5#6{%
  \if@noskipsec \leavevmode \fi
  \par
  \@tempskipa #4\relax
  \@afterindenttrue
  \ifdim \@tempskipa <\z@
    \@tempskipa -\@tempskipa \@afterindentfalse
  \fi
  \if@nobreak
    \everypar{}%
  \else
    \addpenalty\@secpenalty\addvspace\@tempskipa
  \fi
  \@ifstar
    {\@ssect{#3}{#4}{#5}{#6}}%
    {\@dblarg{\@sect{#1}{#2}{#3}{#4}{#5}{#6}}}}

因此,我们通常指定的参数\section只能在两个阶段后被宏吞噬。

另一个很好的例子是,为什么这是很好的做法,这与类别代码的变化有关。一旦参数被使用,它们的类别代码就不能改变。因此,通常使用辅助宏来修改类别代码吞噬任何争论。

还有许多其他例子LaTeX 内核,从基本的字体宏到处理目录,甚至通过以下方式定义新命令\newcommand

\def\newcommand{\@star@or@long\new@command}

同样,另一个宏不接受任何参数,但在将 torch 传递给另一个宏之前执行一些操作。一般来说,这个原则在整个内核和软件包中都得到了很好的应用。

答案2

正如 Werner 的回答所解释的那样,这是常见的做法。所有具有 *-variant 的宏都按以下方式定义:

\newcommand{\foo}{\@ifstar{\@sfoo}{\@foo}}
\newcommand{\@sfoo}[1]{Foo with * applied to #1}
\newcommand{\@sfoo}[1]{Foo without * applied to #1}

或其变体。类似地,具有多个可选参数的宏,例如\makebox必须经过很长的路径来决定是否没有、有一个或两个可选参数:

\newcommand{\bar}{\@ifnextchar[{\@bar@i}{\@bar}}
\def\@bar@i[#1]{\@ifnextchar[{\@bar@ii{#1}}{\@bar@iii{#1}}
\def\@bar@ii#1[#2]#3{Bar has two optional arguments, #1 and #2, and #3}
\def\@bar@iii#1#2{Bar has one optional argument, #1, and #2}
\def\@bar#1{Bar has no optional argument and #1}

情况xparse完全不同:由于 *-variants 和可选参数可以以相当通用的方式指定,因此最好加载全部实际参数:

\usepackage{xparse}
\NewDocumentCommand{\foo}{sm}{%
  \IfBooleanTF{#1}
    {Foo with * applied to #2}
    {Foo without * applied to #2}%
}

\NewDocumentCommand{\bar}{oom}{%
  \IfNoValueTF{#1}
    {Bar has no optional argument and #3}
    {\IfNoValueTF{#2}
       {Bar has one optional argument, #1, and #3}
       {Bar has two optional arguments, #1 and #2, and #3}%
    }%
  }%
}

这就是 LaTeX3 的“未来”。

相关内容