
控制序列\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}
同樣,另一個巨集不帶任何參數,但在將火炬傳遞給另一個巨集之前執行一些操作。一般來說,這個原則在整個核心和套件中得到了很好的應用。
答案2
正如維爾納的回答所解釋的,這是常見的做法。所有具有 * 變體的巨集都以這種方式定義:
\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 的「未來」。