将 Emacs Lisp 程序迁移为词法绑定的过程很简单:
首先,在 Emacs Lisp 源文件的头部行中,添加文件局部变量设置,将 lexical-binding 设为 t(see 文件局部变量);
其次,检查程序中所有需要动态绑定的变量:确保这些变量都有对应的变量定义,避免被意外地词法绑定。
判断哪些变量需要定义的一种简单方法,是对源文件进行字节编译。See 字节编译。如果一个非特殊变量在 let 表达式之外被使用,字节编译器会警告:对自由变量的引用或赋值。如果一个非特殊变量在 let 表达式中被绑定但未被使用,字节编译器会警告:存在未使用的词法变量。如果你将特殊变量用作函数参数,字节编译器同样会发出警告。
出现对自由变量的引用或赋值这类警告,通常明确说明:该变量应当被标记为动态作用域,因此你需要在变量第一次使用之前,添加合适的 defvar 声明。
未使用变量的警告,可能是一个很好的提示:该变量本意是要使用动态作用域(因为它确实在其他函数中被使用),但也可能只是说明:该变量确实完全没用,可以直接删除。
所以你需要判断属于哪种情况,然后据此要么添加 defvar,要么彻底删除该变量。如果无法或不希望删除(通常因为它是形式参数,而你不能或不想修改所有调用处),也可以在变量名前加一个下划线,用来告诉编译器:这个变量是故意不使用的。
警告: 这是一项实验性特性,可能会在未经预先通知的情况下发生变更或被移除。
字节编译器还可以对在其他 Emacs Lisp 文件中被声明为特殊变量的词法变量发出警告,这种情况通常意味着缺少了 defvar 声明。这项实用但较为专业的检查需要三个步骤:
EMACS_GENERATE_DYNVARS 设置为非空字符串,然后对所有你关心其特殊变量声明的文件进行字节编译。这些文件通常是同一个软件包、相关软件包或 Emacs 子系统中的所有文件。此过程会为每个被编译的 Emacs Lisp 文件生成一个以 .dynvars 结尾的文件。
EMACS_DYNVARS_FILE设置为步骤 2 中生成的合并文件的文件名。
下面是一个示例,演示具体如何操作,假设使用 Unix Shell 和 make 工具进行字节编译:
$ rm *.elc # force recompilation $ EMACS_GENERATE_DYNVARS=1 make # generate .dynvars $ cat *.dynvars > ~/my-dynvars # combine .dynvars $ rm *.elc # force recompilation $ EMACS_DYNVARS_FILE=~/my-dynvars make # perform checks