在 \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}

应该总是放在定义代码的最后,因为他们想看看接下来的内容。

相关内容