摆脱“引用自由variables”字节编译警告

我正在写一个emacs主模式,它使用缓冲区局部variables来存储一些状态:

(defun foo-mode () "My nice major mode" (interactive) (kill-all-local-variables) (setq mode-name "foo") (setq major-mode 'foo-mode) (set (make-local-variable 'foo-state) "bar")) (defun foo-change-state () (setq foo-state "baz")) 

这工作得很好,并具有在任何缓冲区不使用我的主要模式的财产foo-statevariables没有约束(这是一个好东西在我看来,因为它避免了混乱的符号表)。

但是,字节编译这样一段代码会产生以下警告:

 Warning: assignment to free variable `foo-state' 

使用defvar摆脱警告,但有副作用, defvar现在到处都是,这在我看来是不可取的。

有没有办法摆脱警告,而仍然没有绑定在每个缓冲区模式特定的variables? 或者当我认为这些variables不应该在全球范围内声明时,我误会了?

官方的做法是(defvar foo-state) 。 注意没有第二个参数。 还要注意,这样的声明只适用于find它的文件。

defvar声明variables。 除此之外,没有其他办法可以去除这个警告了,这是一个很好的做法。

你打算保持符号表的整洁是值得的,但你实际上并不这样做。 我想你已经误解了Emacs Lisp中variables绑定的语义,因为你似乎相信通过不声明它将在没有使用foo-mode缓冲区中解绑定foo-state事实并非如此

在Emacs中,Lisp名称(又名符号)是全局的 。 只要第一次评估foo-state ,运行时就会为foo-state创build一个新的符号对象,并将其放入全局符号表(又名obarray )中。 没有本地符号表,因此在何处评估foo-state以及foo-state如何在任何地方引用同一个符号对象并不重要(请参阅创build符号 )。

每个符号对象由组件(也称为单元)组成,其中之一是variables单元(请参阅符号组件 )。 setq修改系统的当前绑定,在顶级没有词法绑定,这有效地改变了符号对象的variables单元,从而variables的全局值。 同样, setq被评估的地方并不重要。 实际上,如果一些bar-mode评估(setq foo-state "bar")foo-state也会被绑定到foo-mode “bar”,反之亦然。

因此, (defvar)超过(setq)的唯一影响就是将使用符号作为全局variables的意图,因此告诉别人不要修改这个variables,除非对foo-mode的行为进行操纵。 您可以将文档附加到variables,并标记为在缓冲区中定义( Ch v foo-state将提供跳转到定义的链接)。

由于Emacs Lisp缺less名称空间,并且默认情况下是dynamic范围的,所以文档对于避免模块之间的冲突是非常重要的。 如果我用你的foo-mode写了一个bar-mode我可能会不小心将它绑定到foo-state ,然后调用foo-change-state ,然后看到我的模式行为exception,因为一个variables被无意的覆盖了。 声明foo-state并不是不可能的,但它至less可以让我捕捉到错误,因为Ch v foo-state会显示这个variables被另一个模式使用,所以我最好不要使用它,除非我真的打算操纵那种模式。

最后一句话:在前面提到的所有文本中,“模式”都可以用Emacs Lisp文件replace。 关于符号, modes没有什么特别之处。 上述所有内容也适用于不声明模式的Emacs Lisp,只是包含一堆函数。