何时在 \if 语句中使用 @

何时在 \if 语句中使用 @

我是 LaTeX 的新手,所以这个问题可能显得比较基础。它也可能反映了我从事 C/C++ 编程时的偏见/假设。

我查看了“考试”类的代码,发现有些\if<xyz>@,而有些没有。

例如,下面是类文件中的几行代码(按出现/执行的顺序)

  1. \newif\ifcancelspace
  2. \newif\if@addpoints
  3. \def\addpoints{\global\@addpointstrue}
  4. \@addpointsfalse

我无法理解以下内容:

  • 是否使用(在 [4] 中声明的)\if@addpoints的值对 [2] 中的(当它出现时)进行求值@addpoints

  • 在上面的添加点前面添加一个有意义吗@

    • 在类/包文件中命名变量只是良好的编程习惯吗?
    • \def\addpoints或者,这是必要的,因为[3] 中有另一个,并且@需要区分两者?
  • LaTeX 中变量的默认范围是什么?

  • @addpoints当它直到 [4] 才被定义时,如何在 [3] 中使其成为全局的?

答案1

这个问题同时涉及几件事,这使得回答它变得有点有趣。其他人采取了一种策略,我将采取另一种策略。

首先,请记住 TeX 是一种宏扩展语言,而不是函数式语言。其次,请注意 TeX 的内置变量类型非常少。因此,许多“变量”都是具有适当结构的宏。

\newif宏根据参数创建三个新的宏\if<name>

  • \if<name>,测试时使用的开关;
  • \<name>true,将开关设置为逻辑真;
  • \<name>false,将开关设置为逻辑上的假;

通常,\if<name>这里是类似\if@myswitch或的东西\ifmy@switch。其他答案提到@这是一个“字母”,用于命名 TeX 宏。因此,@对于 TeX 来说,没有特殊含义:它只是为程序员而存在。(通常的模式是使用@以使名称更易于阅读,因此\if@<package>@<meaning>\if<package>@<meaning>很常见。)

因此,分析问题,这两行\newif\ifcancelspace\newif\if@addpoints创建宏

  • \ifcancelspace
  • \cancelspacetrue
  • \cancelspacefalse
  • \if@addpoints
  • \@addpointstrue
  • \@addpointsfalse

这两个开关现在可以在建筑中使用

\if@addpoints % or \ifcancelspace
  % Do stuff
\else
  % Do other stuff
\fi

接下来,以点 [4] 为例,宏将开关\@addpointsfalse设置\if@addpoints为逻辑上的 false。因此,这意味着我上面的测试将“执行其他操作”。设置\@addpointstrue意味着测试将“执行操作”。

最后要处理的一点是 [3],为此你需要了解 TeX 中的分组、宏扩展以及开关的实际工作方式。由于 TeX 是一种宏语言,因此它没有在函数“内”使用变量的概念。因此,组是由构造创建的

{ ... }

或者

\begingroup ... \endgroup

(括号组也用于 TeX 需要分组的地方,因此它实际上消失了。例如,需要使用的组就是这种情况\def。)

除非是全局赋值,否则赋值将被困在诸如组内。现在,定义\def\addpoints{\global\@addpointstrue}意味着我们使用的地方\addpoints,TeX 会将其替换为(宏扩展)。我们稍后\global\@addpointstrue会回到,但首先要注意的是,这是一个宏,它扩展为\global\@addpointsture

\let\if@addpoints\iftrue

这是一个赋值,通常仅适用于当前 TeX 组级别。但是,\global前缀表示赋值忽略分组。因此结果是\addpoints将全局将开关设置\if@addpoints为逻辑上为真。

答案2

虽然这没有按顺序回答您的问题,但它确实为您呈现的代码 [1]-[4] 提供了一些指导。

@在 LaTeX 中是保留符号,因此不会像其他字母那样处理。执行\makeatletter会反转此保留,“生成@字母”,因此可以在常规变量中使用。当然,\makeatother会恢复此更改。因此\newif\if@addpoints指定一个名为 的新布尔值@addpoints。执行\@addpointstrue/\@addpointsfalse将其设置为 true/false。

类似地,提供了一个可以以类似方式(或)修改的\newif\ifcancelspace布尔值。我认为在变量中使用背后的动机为宏程序员增加了一个深度层。例如,它允许程序员(比如说)使用类似的东西在所有变量前加上包名前缀。如果是一个非常常见但描述性的变量,其他包可能会与这种重新定义发生冲突。但是,使用前缀可以避免这种情况。所以,从某种意义上说,由于存在大量的包和非常不同的编程风格(以及变量/宏的使用),添加这一层特异性是一种很好的编程习惯。cancelspace\cancelspacetrue\cancelspacefalse@\newif\myfunc@dothisdothis

LaTeX 中变量的默认作用域是它们被声明/修改的组的局部范围。在赋值语句前加上前缀\global会使更改变为全局的,因此存在于进行赋值的组之外。例如,考虑\def\addpoints{\global\@addpointstrue}。这定义了一个名为 的宏\addpoints(通过使用\def,并且该宏执行\global\@addpointstrue。从上面的讨论应该可以清楚地看出,这会将布尔值设置@addpoints为 true。但是,由于宏定义包含在大括号 中{ },因此它定义了一个以 开头{并以 结尾的组}。在此组内所做的任何更改/赋值在其外部都是无效的。由于您使用了\global,这会覆盖作用域以扩展到组之外。也就是说,\@addpointstrue不是“全局的”。相反,修改的作用域是全局扩展的。

具体到最后一条:\newif\@addpoints 布尔值 的定义@addpoints,而\global调整范围(如前所述)。从编程的角度来看, 的使用global可能与变量声明有关。然而,在 LaTeX 中并非完全如此。事实上,它可以在变量声明时使用(以便使声明成为全局声明,如 ,顺便说一下,\global\def\mycommand{...}这相当于\gdef\mycommand{...})或在某些变量修改期间使用。

答案3

@符号在 LaTeX 中经常(但并非唯一)用作“特殊字符”,这意味着(大多数情况下)任何包含包含此字符的命令的宏都必须处于“特殊模式”(好吧,这听起来有点循环!)才能工作。使用命令进入“特殊模式”,\makeatletter使用命令退出\makeatother。LaTeX 内核和许多 LaTeX 软件包定义了供内部使用的命令,这些命令不应在普通编程中直接访问,即由用户访问。为了避免意外使用这些内部命令,通常会为它们提供一个或多个@符号;理论上,用户要访问此类命令,他们必须先明确提供命令,\makeatletter然后才能这样做,在这种情况下(理论上是这样)他们知道自己在做什么……

您提供的示例说明了这一点:指令\newif\if@addpoints创建一个名为的布尔变量,还有什么@addpoints;这是一个内部变量,通常不应直接操作;其默认值为语句的“false” 。另一方面,\@addpointsfalse命令是一个用户级命令,可让您将此变量的状态更改为“true”。\addpoints

当然,这种编程约定并不是完全万无一失的,但经验表明,遵循此约定的代码更加健壮。

相关内容