2013年5月更新:自GNU Emacs 24.3.1起(let(defun..)字节编译很好,没有任何警告,字节编译代码的工作原理与未编译代码相同别忘了将文件变量lexical-binding: t
添加到要字节编译的文件中现在不需要在这个问题结束时采取解决办法。
Lexical Binding - Emacs Lisp Manual这一段:
注意,像symbol value、boundp和set这样的函数只检索或修改变量的动态绑定(即,其符号值单元格的内容)此外,DeFun或DeMe宏的正文中的代码不能引用周围的词汇变量。
我不确定第二句话的意思是否正确在下面的代码中,应该在词法绑定模式下运行,DeFun的正文中的代码成功地引用了名称“cc>的词汇绑定值。
(let ((n 0))
(defun my-counter ()
(incf n)))
(my-counter) ;; 1
(my-counter) ;; 2
这句话只是说(让(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
最佳答案
至少在Emacs24.1.1中,代码的字节编译不好我在foo.el
文件中保存了以下代码,该文件使用setq
代替incf
,以避免cl
库可能产生的任何影响:
;; -*- lexical-binding: t -*-
(let ((n 0))
(defun my-counter ()
(setq n (1+ n))))
当我尝试字节编译它(m-x byte compile filefoo.el)时,得到了以下警告消息:
foo.el:3:1:Warning: Function my-counter will ignore its context (n)
foo.el:3:1:Warning: Unused lexical variable `n'
foo.el:5:11:Warning: reference to free variable `n'
foo.el:5:17:Warning: assignment to free variable `n'
所有的消息都表明,在
defun
构造体中的代码不能引用周围的词法变量n
。实际上,当我加载字节编译代码(M-x load filefoo.elc)并评估
(my-counter)
表单时,得到了以下erorr:Debugger entered--Lisp error: (void-variable n)
...
不幸的是,当以源代码的形式进行计算时,我不确定为什么代码看起来有效。