摆脱“引用自由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-state
variables没有约束(这是一个好东西在我看来,因为它避免了混乱的符号表)。
但是,字节编译这样一段代码会产生以下警告:
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,只是包含一堆函数。