在 \newcommand 中使用 \def

在 \newcommand 中使用 \def

考慮這個例子:

\documentclass{report}
\def\startnewpart{FALSE}
\makeatletter
\renewcommand\chapter{\if@openright\cleardoublepage\else\clearpage\fi                                                                                                                                       
%                    \def\startnewpart{FALSE} 
                    \thispagestyle{plain}%                                                                                                                                                                  
                    \global\@topnum\z@
                    \@afterindentfalse
                    \secdef\@chapter\@schapter
%                    \def\startnewpart{FALSE}                                                                                                                                                               
}
\makeatother
\begin{document}
\tableofcontents
\chapter{Methods}
Some text
\end{document}

如果\renewcommand\chapter我取消註釋第一個, 則\def\startnewpart{FALSE}該文件可以正常編譯。

相反,如果我取消第二個註釋,\def\startnewpart{FALSE}則會收到錯誤:

Chapter 1.
! Missing { inserted.
\@makechapterhead ...1\par \nobreak \vskip 40\p@ }

l.21 \tableofcontents

差別在哪裡呢?

在此範例中,我正在探索如何使用控制變數\startnewpart來控制\chapter.\def\startnewpart{FALSE}的目的是重置 的值\startnewpart

答案1

\secdef定義為

% latex.ltx, line 6086:
\def\secdef#1#2{\@ifstar{#2}{\@dblarg{#1}}}

在你的情況下你得到

\@ifstar{\@schapter}{\@dblarg{\@chapter}}

現在\@ifstar看看下面的標記。如果取消第二\def行的註釋,則下一個標記不是*, 而是\def。因此 LaTeX 發現

\@dblarg{\@chapter}\def\startnewpart{FALSE}

這是 的定義\@dblarg

% latex.ltx, line 1105:
\long\def\@dblarg#1{\kernel@ifnextchar[{#1}{\@xdblarg{#1}}}

這樣你就得到了

\kernel@ifnextchar[{\@chapter}{\@xdblarg{\@chapter}}\def\startnewpart{FALSE}

此巨集\kernel@ifnextchar吸收三個參數,此處為[{\@chapter}和 ,{\@xdblarg{\@chapter}}並檢查下一個標記是否為[。不是,因為是\def,所以效果就是得到

\@xdblarg{\@chapter}\def\startnewpart{FALSE}

好的,讓我們來看看\@xdblarg

% latex.ltx, line 1106:
\long\def\@xdblarg#1#2{#1[{#2}]{#2}}

#1{\@chapter}(但大括號將根據規則被刪除),所以你最終會得到

\@chapter[{\def}]{\def}\startnewpart{FALSE}

這肯定不是您希望在程式碼中出現的內容。

它並沒有真正綁定到\def.命令如

\secdef\A\B
\@ifstar{A}{B}
\@ifnextchar<char>{A}{B}

應該總是在定義代碼中放在最後,因為他們想看看接下來會發生什麼。

相關內容