为什么我不能用 \newcommand 定义以“\end”开头的命令?

为什么我不能用 \newcommand 定义以“\end”开头的命令?

注意:我看到一个看似重复的问题为什么我不能定义以 \end 开头的命令?提供了一个解决方法,但并没有真正回答问题的“为什么”部分。这个问题旨在真正理解“为什么”部分。

示例代码:

\documentclass{article}
\newcommand{\endnote}{endnote}
\begin{document}
hello
\end{document}

输出:

$ pdflatex foo.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./foo.tex
LaTeX2e <2020-10-01> patch level 4
L3 programming layer <2021-02-18>
(/usr/local/texlive/2020basic/texmf-dist/tex/latex/base/article.cls
Document Class: article 2020/04/10 v1.4m Standard LaTeX document class
(/usr/local/texlive/2020basic/texmf-dist/tex/latex/base/size10.clo))

! LaTeX Error: Command \endnote already defined.
               Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              
                                                  
l.2 \newcommand{\endnote}{endnote}
                                  
?

错误消息要求我阅读手册第 192 页。但我不明白它指的是哪本手册。我想知道 LaTeX 拒绝创建以 开头的命令的确切原因\end

答案1

定义时\newenvironment,会创建两个宏。例如,考虑一个名为 的环境note。创建的两个宏是\note\endnote。因此,创建的任何环境都会有一个与之关联的以 开头的宏\end...。新手用户可能没有意识到创建名为 的环境note会绑定名为 的宏\endnote

这个答案可能解释了允许作为宏名的危险\end...。如果在创建相应环境之后发出,它会破坏环境。如果在创建相应环境之前发出,宏会被覆盖。

因此,我的猜测是明确禁止这样做,以避免这种混淆,因为对于新手来说,名为的宏和名为的环境\newcommand之间似乎没有任何联系。\endnotenote

\documentclass{article}
\newenvironment{note}{Note:}{The End}
\begin{document}
\begin{note}
Hi mom
\end{note}

\def\endnote{endnote}
\endnote

\begin{note}
Hi mom
\end{note}

\end{document}

在此处输入图片描述

答案2

环境通常通过 -macro 来定义\newenvironment,其中底层宏和定义\⁠⟨environmentname⟩\end⁠⟨environmentname⟩

如果以这种方式定义环境,则其他内容下方的 -macro 将打开一个新的范围/组,并在该范围/组内通过\begin调用宏。\⁠⟨environmentname⟩\csname ⁠⟨environmentname⟩⁠\endcsname

如果以这种方式定义环境,则其他事物下的 -macro 将通过\end调用宏来关闭 -macro 打开的范围/组。\end⁠⟨environmentname⟩\csname end⁠⟨environmentname⟩⁠\endcsname\begin

\csname ⁠⟨macroname⟩\endcsname交付代币\⁠⟨macroname⟩如果传递的标记在传递时尚未定义\csname..\endcsname,则它将被定义为\relax当前范围/组内的 -primitive。(\relax-primitive 是不可扩展的无操作,它进入了 TeX 的胃中。)

对于 来说,未定义或定义为\relax-primitive 的标记是相同的\newcommand:如果您执行\let\foobar=\relax,那么您之后就可以完美地执行而不会收到有关已定义的\newcommand{\foobar}...错误。实际上并不检查要定义的命令是否未定义。实际上检查要定义的命令是否未定义或等于。如果是这种情况,则将执行定义。如果不是这种情况,即,如果要定义的命令的定义不同于,则会引发有关该命令已定义的错误消息。\foobar\newcommand\newcommand\relax\relax

如果为每个环境定义了一个宏,那么\end⁠⟨environmentname⟩\newcommand禁止定义名称中带有短语“\end”的宏就没有必要了。检查已经定义的(底层)宏与和\relax都足够了。\newcommand\newenvironment

-macro\newenvironment是一种定义环境的好工具,但实际上\begin-macro 和\end-macro“并不关心”底层宏的定义是如何完成的。\⁠⟨environmentname⟩\end⁠⟨environmentname⟩

有时环境不是通过使用来定义的\newenvironment,而是通过直接定义底层宏来定义的,而\⁠⟨environmentname⟩使-macro 未定义\end⁠⟨environmentname⟩,依赖于通过-macro 调用会产生-no-op的情况,因为在当前环境的范围/组内宏是未定义的。\csname end⟨environmentname⟩⁠\endcsname\end\relax\end⁠⟨environmentname⟩

\end...因此,禁止在名称中定义带有的宏可以防止意外/错误地为不应定义的环境定义宏。\end⁠⟨environmentname⟩

相关内容