蚊章汇 - Clemens Radermacher
type: channel
link: https://linuxcn.bwsl.wang/author/1395/
description: Clemens Radermacher
items: 关于 Emacs 中的变量你需要知道的事情

关于 Emacs 中的变量你需要知道的事情
type: item
date: 2020-04-26T03:09:00+08:00
description: 学习 Elisp 是如何处理变量的，以及如何在你的脚本与配置中使用它们。GNU Emacs 是由 C 和 Emacs Lisp（Elisp，Lisp 编程语言的一种方言）写成，它是一个编辑器的同时，又碰巧是 Elisp 的沙盒。因此，理解 Elisp 中的一些基本编程概念会对你有一些帮助。如果你是 Emacs 新手，请先阅读 Sacha Chua 的《给 Emacs 新手的资源》精品帖。本篇文章假定你熟悉常见的 Emacs 术语，并且能够阅读并求值 Elisp 代码的简单片段。最好你也听说过变量作用域的概念，知道它在其它编程语言中的作用。本篇文章中的示例假定你使用的是相对较新的 Emacs 版本（v.25 之后的版本）。Elisp 手册 包含了 Elisp 的方方面面，但它是写给那些有明确查找目标的人们的（它在这方面也做得相当棒）。但是很多人想要能够在更高的层次上解释 Elisp 概念的材料，同时将信息压缩成最精华的部分。本篇文章也正是我回应这种呼声的一次尝试，为读者描绘基础的大体轮廓。使他们能在配置中用上这些技巧，也让他们在手册中查询细节变得更容易。全局变量用 defcustom 定义的用户设置和用 defvar 或 defconst 定义的变量是全局的。使用 defcustom 或 defvar 声明变量的一个非常重要的原因是，当一个变量已经被 绑定 bind ，对它们进行重新求值不会覆盖掉已有的值。举个栗子，如果你在初始化文件中对 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 的代码搜索发现更复杂的变体）。(defmacro csetq (sym val) `(funcall (or (get ',sym 'custom-set) 'set-default) ',sym ,val))若你正在使用 use-package 宏，:custom 关键字会替你处理好以上这些。在你将以上代码放入到你的初始化文件中之后，你便可以使用 csetq 宏在设置变量的同时运行任何现存的 setter 函数。要证明这点，你可以使用此宏来改变上面定义的选项，并观察回显区域的消息输出。(csetq my-option nil)动态绑定与词法绑定当你在使用其它编程语言时，你可能不会意识到动态绑定与词法绑定的区别。当今的大部分编程语言使用词法绑定，并且在学习变量作用域与变量查找时也没有必要去了解它们之间的区别。如此看来，Emacs Lisp 比较特殊因为动态绑定是默认选项，词法绑定需要显式启用。这里有一些历史遗留原因，但在实际使用中，你应该时刻启用词法绑定，因为它更快并且不容易出错。要启用词法绑定，只需将如下的注释行作为你的 Emacs Lisp 文件的第一行：;;; -*- lexical-binding: t; -*-另一种方式，你可以调用 add-file-local-variable-prop-line，在你…