变量定义(variable definition) 是一种语法结构,用于声明你打算将一个符号用作全局变量。它使用特殊形式 defvar 或 defconst,这两者的说明见下文。
变量定义有三个作用:第一,它告诉阅读代码的人,这个符号 被设计 以某种方式(作为变量)使用;第二,它将这一信息告知 Lisp 系统,并可选择性地提供初始值与文档字符串;第三,它为诸如 etags 之类的编程工具提供信息,使这些工具能够找到该变量的定义位置。
defconst 与 defvar 的区别主要在于意图,用于告诉阅读代码的人该变量的值是否应该被修改。Emacs Lisp 实际上并不会阻止你修改由 defconst 定义的变量。两者一个明显的区别是:defconst 会无条件初始化变量,而 defvar 只在变量原本为空(void)时才进行初始化。
若要定义一个可自定义变量,你应当使用 defcustom(它会在内部调用 defvar)。See 定义自定义变量。
该特殊形式将 symbol 定义为变量,并可选择性地对其进行初始化和文档注释。注意,它不会对 symbol 进行求值;待定义的符号需显式出现在 defvar 形式中。defvar 还会将 symbol 标记为 特殊(special),这意味着该符号的绑定应始终为动态绑定(see Scoping 变量绑定的作用域规则)。
若指定了 value,且 symbol 处于空(void)状态(即无动态绑定值;see 变量为空的情况),则 defvar 会对 value 求值,并将求值结果赋值给 symbol 以完成初始化。但如果 symbol 非空,defvar 不会对 value 求值,且保留 symbol 的原有值不变。若省略 value,则 defvar 在任何情况下都不会改变 symbol 的值。
需注意,只要指定了 value(即便值为 nil),该变量就会被永久标记为特殊变量;而若省略 value,defvar 仅会将该变量局部标记为特殊变量(即:在当前词法作用域内,或若 defvar 出现在顶层,则在当前文件内)。这一特性可用于抑制字节编译警告,详见 编译器错误。
若 symbol 在当前缓冲区中存在缓冲区局部绑定,且此时指定了 value,则 defvar 会修改 symbol 的默认值(该值与缓冲区无关),而非修改其缓冲区局部绑定。仅当默认值为空时,它才会设置该默认值。See 缓冲区局部变量。
若 symbol 已被 let 绑定(例如 defvar 形式出现在 let 形式内部),则 defvar 会设置 symbol 的顶层默认值,行为与 set-default-toplevel-value 类似。该 let 绑定会一直生效,直到其所属的绑定结构执行完毕。See Scoping 变量绑定的作用域规则。
在 Emacs Lisp 模式下,当你使用 C-M-x(对应函数 eval-defun)或 C-x C-e(对应函数 eval-last-sexp)对顶层的 defvar 形式求值时,这两个命令有一个特殊机制:它们会无条件地设置该变量的值,而不会先检查变量是否为空(void)。
若提供了 doc-string 参数,该参数会为变量指定文档字符串(文档字符串会存储在符号的 variable-documentation 属性中)。See Documentation。
以下是一些示例。这个形式定义了 foo,但并未对其进行初始化:
(defvar foo)
⇒ foo
本例将 bar 的值初始化为 23,并为其提供了文档字符串:
(defvar bar 23
"The normal weight of a bar.")
⇒ bar
defvar 形式的返回值是 symbol,但它通常用在文件的顶层位置,此时其返回值并不重要。
若想查看更详细的「无值使用 defvar」示例,请参见 Local defvar example。
该特殊形式将 symbol 定义为变量并对其初始化。它告知阅读代码的人:symbol 拥有在此处定义的标准全局值,用户或其他程序不应该修改它。注意:symbol 不会被求值;要定义的符号必须显式写在 defconst 中。
与 defvar 一样,defconst 会将该变量标记为特殊(special),表示它始终使用动态绑定(see Scoping 变量绑定的作用域规则)。此外,它还会将变量标记为风险变量(risky)(see 文件局部变量)。
defconst 总会对 value 求值,并将结果设为 symbol 的值。如果 symbol 在当前缓冲区中有缓冲区局部绑定,defconst 只会设置默认值,而不是缓冲区局部值。(但你不应该为用 defconst 定义的符号建立缓冲区局部绑定。)
defconst 的一个使用例子是 Emacs 里对 float-pi 的定义 — 数学常量 \(pi\),任何人都不应该修改它(尽管印第安纳州议会曾试图这么做)。不过,正如后一段代码所展示的,defconst 只起到提示作用,并非强制不可修改。
(defconst float-pi 3.141592653589793 "The value of Pi.")
⇒ float-pi
(setq float-pi 3)
⇒ float-pi
float-pi
⇒ 3