2013 年 5 月更新:从 GNU Emacs 24.3.1 开始,(let .. (defun..)) bytecompiles 很好,没有警告,bytecompiled 代码与未编译代码一样工作。只是不要忘记将文件变量添加lexical-binding: t
到要进行字节编译的文件中。现在不需要在此问题末尾的解决方法。
Lexical Binding - Emacs Lisp Manual有这一段:
请注意,symbol-value、boundp 和 set 等函数仅检索或修改变量的动态绑定(即其符号值单元格的内容)。此外,defun 或 defmacro 主体中的代码不能引用周围的词法变量。
我不确定我是否理解了第二句话的意思。在下面应该以词法绑定模式运行的代码中,defun 主体中的代码成功地引用了 name 的词法绑定值n
。
(let ((n 0))
(defun my-counter ()
(incf n)))
(my-counter) ;; 1
(my-counter) ;; 2
这句话只是说 (let .. (defun ..)) 是一种不好的做法吗?
解决方法:
;; -*- lexical-binding: t -*-
;; a way to define the counter function without byte-compile error or warning
(defvar my--counter-func
(let ((n 0))
(lambda ()
(setq n (1+ n)))))
(defun my-counter ()
(funcall my--counter-func))
;; another way to define the counter function, again without byte-compile error or warning
(fset 'my-another-counter
(let ((n 0))
(lambda ()
(setq n (1+ n)))))
这是测试上述代码的代码:
;; run:
;; emacs -q --load path-to-the-el-file-of-this-code.el
(load "path-to-file-defining-my-counter.elc") ;; loading the ELC file to test if byte-compiled code runs as expected.
(print (my-counter)) ;; 1
(print (my-counter)) ;; 2
(print (my-another-counter)) ;; 1
(print (my-another-counter)) ;; 2