毫无疑问,字体大小开关以控制序列的形式存在(在这里例如。)但是,有时我会遇到使用环境版本的代码示例,例如\begin{small}...\end{small}
。在成功测试这些代码后,我开始将它们合并到我的 TeX 词汇表中。
几天前@GonzaloMedina 在我的回答中评论说这些环境并不存在,依赖它们的构造纯属巧合。然后我试图了解更多关于这些不祥环境的信息。不祥是因为它们似乎没有以某种方式记录下来。(我发现的唯一试图以某种系统的方式解释它们的是一些 Wikibooks 资源。)
这些环境是真实的吗?
答案1
您可以使用LaTeX
由定义的任何命令\newcommand
并将\begin{}...\end{}
其包装成一对,但是,我们不建议这样做,因为这不是一个环境。
然而有趣的是,分组无论如何都有效,但这是的结果\begin...\end
。
没有像\begin{small}
etc 这样的字体大小环境,因为没有\begin{chapter}
etc。
例如:
\documentclass{article}
\newcommand{\foo}{This does nothing}
\begin{document}
\begin{foo}
\end{foo}
\end{document}
编辑一些解释
此代码可以在中找到latex.ltx
,参见第 4058f 行。
\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}
可以看出,@ifundefined{foo}
将会调用 ,这是错误的,因为它\foo
已被定义,所以environment
名称foo
被设置并且\csname #1\endcsname
(即\foo
)被调用。
现在是\end{foo}
: 部分
\def\end#1{%
\csname end#1\endcsname\@checkend{#1}%
\expandafter\endgroup\if@endpe\@doendpe\fi
\if@ignore\@ignorefalse\ignorespaces\fi}
环境查找\end...
代码,此处\endfoo
未定义,但\csname endfoo\endcsname
扩展为,\relax
并且没有发生任何不好的事情。
需要注意的是,许多众所周知的环境并没有用 来定义\newenvironment
。使用\foo
命令 和就足够了,例如\def\endfoo
参见\endequation
或等。\endenumerate
答案2
任何命令都可以用作环境,如果围绕大块文本,通常很方便,因此
{\small zzz\par}
和
\begin{small}%
zzzz
\end{small}
或多或少是等价的。
但请注意,与 不同,由于正常的 TeX 标记化规则,\small
后面的空格不会被删除。此外,您几乎总是需要在 之前添加一个 或 空行,这在命令形式中也是如此,但在环境形式中更容易忘记,因为大多数自定义环境(例如)在其结束代码中包含一个隐式,但这里的情况并非如此。\begin{small}
\par
\end
center
\par
另请参阅以下讨论:
答案3
实际上,“LaTeXbook”(正确的名称应该是“LaTeX. 一种文档准备系统”,作者是 Leslie Lamport)支持使用此类环境:在第 27 页的末尾我们发现:
每个声明都有一个对应的同名环境(减去字符
\
)。输入\begin{em} ... \end{em}
相当于输入
{\em ... }
。
具体来说,“环境”形式会自动提供一个组,以保持声明的效果在本地,就像环境中总是发生的那样(\begin
发出一个\begingroup
,以及\end
相应的\endgroup
)。现在,\small
是一个声明,因此上述内容适用。
这样做是故意的,因此我认为说这些环境“偶然”起作用是不对的;事实上,正如已经观察到的,缺少类似命令的定义\endsmall
不会引起任何问题,因为它被称为\csname small\endcsname
,因此等同于\relax
if undefined。
所以,最后我的回答是:“是的,这些环境是‘真实的’”(不管这意味着什么)。
添加
看到一些评论后,我觉得补充一些关于 LaTeX2e 中环境实现方式的细节可能会很有用(我不会谈论 LaTeX3,因为我没有足够的专业知识)。 Christian Hupfer 已经提供了确切的代码摘录latex.ltx
,但也许有人会发现以下补充说明也很有用。
当您定义环境时FOO
,LaTeX 只需定义两个新命令\FOO
和\endFOO
:后者始终没有参数,而前者具有为环境指定的相同参数(如果有)FOO
。 当\begin{FOO}
遇到时,会发生以下事情(其中包括):
一个组以 开始
\begingroup
;\begin
(在本例中)的参数FOO
被(本地)保存在宏中\@currenvir
,以便稍后能够检查每个参数是否\end
与正确的配对\begin
;该命令
\FOO
作为最后一项命令执行;因此,它将吸收后面的参数\begin{fOO}
(如果存在)。
另一方面,当 LaTeX 出现时\end{FOO}
,会发生以下情况(除其他事项外):
\endFOO
如果它被定义,则执行(如果它未被定义,则什么也不会发生,如上所述);LaTeX 检查的参数
\end
是否等于\@currenvir
,如果不相等,则抛出错误;\endgroup
发出一个通知来关闭该群组。
实际上,当我基于另一个标准环境定义新环境时,我倾向于避免使用显式的\begin
和\end
,这样 的值\@currenvir
就不会改变。例如,假设我想定义一个quote
环境变体,使其内容以斜体显示;我更喜欢,比如说,
\newenvironment{italquote}{%
\quote
\itshape
}{\endquote}
超过
\newenvironment{italquote}{%
\begin{quote}%
\itshape
}{\end{quote}}
尤其是如果我自己不打算使用环境的话。这样,如果用户在语句中拼错了环境的名称\end
,他们就会收到有关错误终止环境的错误italquote
,而这正是他们实际使用的环境,而不是有关错误终止环境的错误quote
,因为他们可能不知道这一点。