\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 的“未来”。