Skip to content

如果你曾经尝试过阅读一些宏包或模板的源码,那么你一定见到过一大堆的带 @ 符号的命令,是不是看得很头疼呢?按理来说呢,变量/函数的命令方式是为了让其变得更加易读,可 LaTeX 的这个 @命名法 似乎让其变得更加难读了.

其实呢更多的还是心理障碍,看到一大堆 @ 总会让人感觉头疼,这和刚学习 LaTeX3 的时候看到那长长的命名规则一样,但是习惯之后就好了.

为什么要使用 @ 参杂在命令名里面,这得先了解一下 catcode,中文翻译为类别码 category code. TeX 中的所有字符都分配有 catcode,总共有 16 个 catcode,如下表所示

Catcode含义描述
0Escape character默认是反斜杠 \. 用于引入控制序列和其他特殊符号.
1Begin group左花括号 {. 用于开始一个组.
2End group右花括号 }. 用于结束一个组.
3Math shift美元符号 $. 用于开始和结束数学模式.
4Align tab&. 在表格和对齐环境中使用.
5End of line换行符(例如 \n\r). 表示一行的结束.
6Parameter#. 用于宏参数的表示.
7Superscript^. 在数学模式中用于上标.
8Subscript_. 在数学模式中用于下标.
9Ignored character空格字符. 会被忽略,除非在某些特定环境下(如 \verb).
10Space空格字符. 被解释为空格,但可以用来分隔控制序列.
11Letter字母字符. 用于构成控制序列的名称.
12Other character其他字符. 可以直接使用,但没有特殊含义.
13Active character活动字符. 通常是 ~,可以定义为宏.
14Comment character%. 用于注释,直到行结束.
15Invalid character不合法字符. 通常是非 ASCII 字符,会引起错误.

这里并不打算一一详细介绍这些 catcode,只介绍 11 和 12

  • 11(letter character), 代表的是所有拉丁字母, 即 A-Za-z
  • 12(other character), 代表的是其它字符, 例如 @

在 LaTeX 中,一个命令通常是由一个 catcode0 的字符(通常为 \)开始,然后紧跟着一堆 catcode11 的字符(通常为拉丁字母 A-Za-z)组成. 所以诸如 \foo123acd, \bar@abc 这些都是不合法的.

在命令行使用

shell
latexdef -s makeatletter
latexdef -s makeatother

分别得到

tex
% latex.ltx, line 1693:
\DeclareRobustCommand\makeatletter{\catcode`\@11\relax}
% latex.ltx, line 1694:
\DeclareRobustCommand\makeatother{\catcode`\@12\relax}

可见 \makeatletter 实际上就是 \catcode\@ = 11, 功能就是将 @catcode 改为 11, 其实 makeatletter 就是 make @ letter,当 @catcode 改成 11 后,依照上面的规则,此时 @ 就和普通的拉丁字母无异了,\bar@abc 便是合法的变量名了.

接下来看一些变量名, \easytoolsrangetolist, \easytoolsgetlength, \easytoolspaperwidth, \easytoolsifshowframe, 解释一些这些命令, \easytoolsrangetolist 其中 easytools 是模块名(通常是宏包或者模板名字), 用它作为前缀方便区分命令是哪个宏包/模板提供的, 也变相的为 LaTeX 提供了 “命名空间” 防止命令名重复, rangetolist 是变量/函数的名字. 但是一大串的字母堆叠在一起,分词的时候还是挺费劲的. 在其它语言中有驼峰命名和下划线命名等方法, \EasytoolsRangeToList, \easytoolsRangeToList, \esaytools_range_to_list 这些命名方案都要比 \easytoolsrangetolist 好得多.

再接下来需要聊一聊私有变量/函数的问题了,当你在写一个宏包或者模板的时候,你会定义很多变量/函数,但是实际给用户用到的也就那么几个,其它命令/函数称为私有命令/函数,这部分使开发者不希望用户直接使用和修改它们的,这时候便可以通过改变 @catcode 为 11, 使得可以在命令中加入 @ 而变成 \easytools@range@to@list.

由于在普通的 .tex 文件中,@catcode 为 12, 所以无法直接使用带 @ 的命令,这就能够避免用户修改和使用开发者定义的私有命令/函数,然而在 .sty.cls 文件中,@catcode 已经被修改成 11 了,可以直接只用它作为命令名的一部分.

如果非要在 .tex 文件中使用和修改私有变量/函数呢,这就需要使用 \makeatletter@catcode 改成 11, 最后再使用 \makeatother@catcode 恢复回来. 只是在使用它们的时候希望你清楚你在做什么,否则不建议使用它们.

latex
\makeatletter % changes the catcode of @ to 11
<your changes here>
\makeatother % changes the catcode of @ back to 12

总结一下,\makeatletter\makeatother 是用来修改和恢复 @catcode 的,使用 @ 作为命令名的组成部分主要有两个方面的作用

  • 断词分割符
  • 私有变量/函数
  • ...