摆脱“引用自由变量”字节编译警告
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了摆脱“引用自由变量”字节编译警告相关的知识,希望对你有一定的参考价值。
我正在写一个emacs主模式,它使用缓冲区局部变量来存储一些状态:
(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
变量没有绑定(在我看来这是一件好事,因为它避免了符号表的混乱)。
但是,对这段代码进行字节编译会产生以下警告:
Warning: assignment to free variable `foo-state'
使用defvar
摆脱警告,但有副作用,foo-state
现在到处都是,这在我看来是不可取的。
有没有办法摆脱警告,同时仍然没有绑定每个缓冲区中特定于模式的变量?或者当我认为这些变量不应该在全球范围内宣布时,我错了吗?
做你想要的官方方式是(defvar foo-state)
。注意没有第二个参数。另请注意,此类声明仅适用于找到它的文件(如果在函数内部使用,则适用于找到它的范围)。
用defvar
声明变量。没有其他方法可以删除警告,这确实是一种很好的做法。
你保持符号表整洁的意图是值得的,但你实际上并没有这样做。我认为你误解了Emacs Lisp中变量绑定的语义,因为你似乎相信通过不声明它foo-state
将在任何不使用foo-mode
的缓冲区中被解除绑定。事实并非如此。
在Emacs中,Lisp名称(又名符号)是全局的。第一次评估foo-state
时,运行时为foo-state
创建一个新的符号对象,并将其放入全局符号表(aka obarray
)。没有本地符号表,所以foo-state
的评估位置和foo-state
在任何地方指的是相同的符号对象都无关紧要(参见Creating Symbols)。
每个符号对象由组件(也称为单元格)组成,其中一个是可变单元格(请参阅Symbol components)。 setq
修改系统的当前绑定,在顶层没有词法绑定,这有效地改变了符号对象的可变单元格,从而改变了变量的全局值。再次,setq
的评估位置无关紧要。实际上,如果一些bar-mode
评估(setq foo-state "bar")
,foo-state
也将被绑定在foo-mode
的“bar”,反之亦然。
因此,(defvar)
对(setq)
的唯一影响就是记录了使用符号作为全局变量的意图,因此告诉其他人不要修改这个变量,除非打算操纵foo-mode
的行为。您可以将文档附加到变量,并标记为在缓冲区中定义(C-h v foo-state
将提供跳转到定义的链接)。
由于Emacs Lisp缺少命名空间,并且 - 默认情况下 - 动态范围,因此文档对于避免模块之间的冲突至关重要。如果我使用你的bar-mode
写了一个foo-mode
我可能会意外绑定到foo-state
,请调用foo-change-state
,然后看到我的模式行为不端,因为变量被无意中覆盖了。声明foo-state
不会让这不可能,但它至少可以让我捕捉错误,因为C-h v foo-state
会发现这个变量被另一个模式使用,所以我最好不要使用它,除非我真的打算操纵那个模式。
总而言之:在所有上述文本中,“模式”可以替换为Emacs Lisp文件。 modes
在符号方面没什么特别之处。以上所有内容也适用于Emacs Lisp,它不声明模式,但只包含一堆函数。
以上是关于摆脱“引用自由变量”字节编译警告的主要内容,如果未能解决你的问题,请参考以下文章