假设我想定义一个新环境,它是现有环境的变体。例如,我寻求一个与现有环境italicquote
行为相同quote
但内容以斜体显示的环境。LaTeX 伴侣是按照在正文中使用的方式来编写内部环境,即
\newenvironment{italicquote}{%
\begin{quote}%
\itshape
}{%
\end{quote}%
}
然而,在这回答定义我自己的描述环境Martin Scharrer 主张将内部环境写成简单的形式,即将我的例子转化为
\newenvironment{italicquote}{%
\quote
\itshape
}{%
\endquote
}
他的理由是:
内部环境以 [...] 的纯格式写入,以避免在
\end{italicquote}
缺少 [ ] 时混淆错误消息。在这种情况下,最后一个\begin
将是内部宏的名称,其名称将打印在错误消息中,而不是源文件中写入的名称。对于您自己的小环境来说,这不是问题,但如果它们被其他人使用,则很重要。
第二种定义“派生”环境的方式是否无一例外地更受青睐?如果是,那么为什么LaTeX 伴侣使用第一种方式?如果不是,那么在我的示例环境中,在什么情况下应该更喜欢写\begin{quote}
... ?\end{quote}
答案1
我被告知要对内部环境使用“普通形式”的原因是,正如问题中已经引用的那样,如果正常\begin
\end
使用正常的/形式并且最后一个\end{<outer env>}
缺失或放错位置,则错误消息将包含最后一个的名称内 \begin{<env>}
。用户可能不知道外部环境在内部使用此环境,因此可能会感到困惑。由于它可以是多个使用环境的一部分,因此错误不会提供太多有关查找位置的信息(除了行号,如果您坚持每行一个,那么行号可能就是您所需要的全部信息\begin
)。
\begin
让我们看看和的定义,\end
看看这两种形式之间的确切区别是什么:
\def\begin#1{%
\@ifundefined{#1}%
{\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
{\def\reserved@a{\def\@currenvir{#1}%
\edef\@currenvline{\on@line}%
\csname #1\endcsname}}%
\@ignorefalse
\begingroup\@endpefalse\reserved@a}
因此\begin
检查#1
(环境名称)是否存在于宏中,如果不存在则报告错误。否则将保存当前列表和名称。后者为\@currenvir
。这是在用打开的组中完成的\begingroup
。@ignore
开关用于忽略后面的空格,而开关@endpe
用于“在段落制作环境之后立即抑制文本中的段落缩进”(来源2e)。
\def\end#1{%
\csname end#1\endcsname\@checkend{#1}%
\expandafter\endgroup\if@endpe\@doendpe\fi
\if@ignore\@ignorefalse\ignorespaces\fi}
宏\end
执行\end<envname>
。然后检查使用\@checkend
的名称是否等于上次打开的\begin
。如果两者不相等,则打印错误消息。然后执行代码\@doendpe
以抑制段落缩进(如果已启用)并关闭该组。如果已启用,则可能会忽略空格。
让我们看看区别:如上面的代码描述所示,如果使用普通的 LaTeX 格式,还会做以下事情:
- 检查其存在性。
- 已添加群组。
- 环境名称已保存。
- 环境开始的行号被保存。
- 之后的空格可以被忽略。
- 可以避免段落缩进。
我们的内部环境需要这些东西吗?:
- 不是,应该知道内部环境是否存在。
- 外部环境已添加一个组,并且几乎从不需要一个额外的组。一个例外是逐字以及其他特殊环境,如果不采取额外的预防措施,这些环境无论如何都无法嵌套。可能有一些非逐字环境需要为其自身设置一个内部组,但这些环境不应依赖于
\begin
/添加的组\end
,而应明确添加。无论如何,如果需要,可以手动添加该组。 - 这是应该直接避免的事情。
- 已被外界环境所拯救。
- 可以通过外部环境来完成,并且因为
\end{xxx}
以 结尾}
所以它不需要删除空格,所以这是必需的。但是普通形式\endxxx
确实需要删除空格,因此不需要删除空格。\ignorespaces
如果有人坚持,可以添加显式的。 - 这一点是我在写这个答案时才发现的最重要的一点:段落是否应该缩进。这似乎在某些环境的开始代码中设置为 true,并在执行后在内部重新设置为 false
\end
。因此,如果使用普通版本,它将移动到外部,\end
这可能是也可能不是正确的事情。我建议在最后手动将开关设置@endpe
为正确的值以避免出现问题。
结论:
只要处理好预期的段落缩进,使用普通形式作为内部环境应该没有问题。它们的优点是可以生成有意义的错误消息,而且速度稍快,不会生成(通常)不必要的子组。特殊的内部环境可能需要特别小心。