[Emacs Lisp] 启用变量的词法作用域

1. setq lexical-binding失效

从Emacs 24开始,Emacs可以启用变量的lexical binding模式,
Emacs Lisp Reference:11.9.4 Using Lexical Binding中提到,

When loading an Emacs Lisp file or evaluating a Lisp buffer, lexical binding is enabled if the buffer-local variable lexical-binding is non-nil:

—— Variable: lexical-binding
If this buffer-local variable is non-nil, Emacs Lisp files and buffers are evaluated using lexical binding instead of dynamic binding. (However, special variables are still dynamically bound; see below.) If nil, dynamic binding is used for all local variables. This variable is typically set for a whole Emacs Lisp file, as a file local variable.

Note that unlike other such variables, this one must be set in the first line of a file.

然而,以下代码,M-x eval-buffer之后,仍然会报错,
仍然使用了变量的dynamic binding模式,

(setq lexical-binding t)

(setq test (let ((foo "bar"))
         (lambda () 
           foo)))

(let ((foo "something-else"))
  (funcall test))    ; "something-else"

(funcall test)    ; Error! Symbol’s value as variable is void: foo

注:
(1)依次对每个表达式使用:M-x eval-last-sexp(快捷键:C-x C-e),
是不会报错的,确实启用了词法作用域。
但是使用M-x eval-buffer求值整个buffer,或者在其他文件中load本文件时,就会报错。
(2)M-x eval-buffer,可以简写为M-x ev-b

2. 解决方案

将文件的第一行改成:; -*- lexical-binding: t -*-
Emacs Version: 25.2

例如:M-x eval-bufferload都不报错,启用了词法作用域。

; -*- lexical-binding: t -*-

(setq test (let ((foo "bar"))
         (lambda () 
           foo)))

(let ((foo "something-else"))
  (funcall test))    ; "bar"

(funcall test)    ; "bar"

注:
(1); -*- lexical-binding: t -*-必须位于文件或者buffer的第一行。
(2)这条指令是以注释的方式存在的,在-*- ... -*-外面可以写任何其他注释,此外多个“;”肯定也是可以的“;;”,例如:;; 123 -*- lexical-binding: t -*- 456

3. File Variables

-*- mode: modename; var: value; ... -*-
类似这样的写法,实际上是在Emacs中指定了File Variables。

GNU Emacs manual: 51.2.4.1 Specifying File Variables中指出,

There are two ways to specify file local variable values: in the first line, or with a local variables list.

Here's how to specify them in the first line:

-*- mode: modename; var: value; ... -*-

A local variables list starts with a line containing the string ‘Local Variables:’, and ends with a line containing the string ‘End:’. In between come the variable names and values, one set per line, like this:

/* Local Variables:  */
/* mode: c           */
/* comment-column: 0 */
/* End:              */

参考

GNU Emacs manual
GNU Emacs Lisp Reference Manual
Emacs Wiki: Lexical binding

你可能感兴趣的:([Emacs Lisp] 启用变量的词法作用域)