全局变量
用 defcustom
定义的用户设置和用 defvar
或 defconst
定义的变量是全局的。使用 defcustom
或 defvar
声明变量的一个非常重要的原因是,当一个变量已经被绑定,对它们进行重新求值不会覆盖掉已有的值。举个栗子,如果你在初始化文件中对 my-var
进行如下绑定:
-
(setq my-var nil)
对如下表达式求值不会将变量覆盖为 t
:
-
(defvar my-var t)
注意此处有一个例外:如果你用 C-M-x
快捷键对上述声明求值,它将调用 eval-defun
函数,并将变量覆盖为 t
。通过此方式,你可以按需将变量强制覆盖。这种行为是刻意而为之的:你可能知道,Emacs 中的许多特性是按需加载的,也可以称为自动加载。如果那些文件中的声明将变量覆盖为它们的默认值,那它也就覆盖了你初始化文件中的设置。
用户选项
用户选项就是使用 defcustom
声明的全局变量。与使用 defvar
声明的变量不同,这些变量可以用 M-x customize
界面来配置。据我所知,大部分人因为觉得它开销较大而不经常使用。一旦你知道如何在你的初始化文件中设置变量,也就没有理由一定要去使用它了。许多用户没有意识到的一个细节是,通过 customize
的方式设置用户选项能够执行代码,有的时间可用来运行一些附加的配置说明:
-
(defcustom my-option t
-
"My user option."
-
:set (lambda (sym val)
-
(set-default sym val)
-
(message "Set %s to %s" sym val)))
若你对这段代码求值,并键入 M-x customize-option RET my-option RET
运行 customize
界面,lambda 匿名函数就会被调用,回显区域就会显示出该选项的符号名与值。
如果你在初始化文件中使用 setq
改变该选项的值,那么匿名函数不会运行。要想在 Elisp 中正确设置一个选项,你需要使用函数 customize-set-variable
。或者,人们在他们的配置文件中使用了各种版本的 csetq
宏来自动处理(如你所愿,你可以通过 GitHub 的代码搜索发现更复杂的变体)。