setq-local是做什么的,什么时候应该使用它?


16

即使在阅读了SX上的所有文档和大量帖子之后,我也不太清楚缓冲区局部变量的所有变体。

以下是我的理解摘要:

(defvar foo ..)为文件声明一个动态变量。但是该变量是(1)其他文件不知道的变量,除非它们也包含一条defvar 语句,并且(2)该变量的作用域是全局的,而不是局部于缓冲区的。

(make-variable-buffer-local foo)之后,defvar上述告诉编译器和其他人,变量foo是被当作缓冲区局部处处设置了,当它是集。因此,此模式是声明缓冲区局部变量,将两个语句背靠背放置在文件中的好样式。

(defvar xxx ...)                    ;declare xxx with global scope
(make-variable-buffer-local 'xxx)   ;but now make it buffer-local everywhere

为了方便起见,该(defvar-local xxx ...)表格可以用作一行,代替上面的两行:

(defvar-local xxx ...)       ;make xxx buffer local everywhere

一旦如上所述声明,变量xxx就可以像setq语句中的任何其他变量一样使用。

如果我只想拥有一个已经是全局动态变量的局部缓冲区变量的实例,则可以使用以下声明。第一个声明全局变量动态变量,第二个语句仅在当前缓冲区中创建该变量的本地缓冲区版本的一个实例:

(defvar xxx ...)             ;declare xxx with global scope
(make-local-variable 'xxx)   ;make xxx local in this buffer only

现在是我的明确问题(以上所有都是关于我的理解是否正确的隐性问题)。

设置变量的值时,可以使用setqsetq-local。什么时候应该setq-local使用?为什么?

如果我setq-local在局部缓冲区变量或非局部缓冲区变量上使用会怎样?

声明的变量是setq-local必需的defvar-local吗?

setq-local普通defvar声明的变量转换为局部缓冲区变量吗?(换句话说,它在setq-local某种程度上等同于(make-variable-local xxx)声明吗?


感谢Scott的辛勤工作。我将投入额外的反引号从这里英寸
凯文-

2
(setq-local VAR VALUE)是的简写(set (make-local-variable VAR) VALUE),这曾经是(现在仍然是)一个惯用语。
提请

Answers:


18

您的大多数假设都是接近的。我待会再提及。但是,首先是主要问题。

形式setq-local只是一种方便,它与make-local-variable后面的操作相同setq。如果您已经完成了C-h f setq-local查看文档的操作并单击了源代码,则可能已经看到了。这就是我验证第一印象的方式。但是,该代码有些晦涩,因为它正在优化诸如make-local-variable实际返回变量本身的事实。使用setq-local是指出某些代码中局部性的一种方式,以便其他人知道该代码无法使用变量的全局值。你不是需要用它来访问本地变量。可以将任何变量设置为局部缓冲区,这将影响所有与该变量相关的代码(除非它竭尽所能地获取具有setq-default或类似变量的全局副本)。

那是主要的答案。现在,您的背景中有些事情还差得远。既然您问过这个问题,我就解决一些问题。

第一个是“其他文件未知”。这不是真的。任何代码都可以引用任何全局变量(这就是为什么它们被称为“全局”)的原因,而无需包含defvar(并C-h f defvar如此)。实际上,每个全局变量应该只有一个defvar变量(带有文档字符串和默认值)。defvar仅带有变量名的A 可用于禁止字节编译器警告。Emacs仅使用它看到的第一个值¹,而使用最后一个的文档字符串。如果有多个defvar带有值/文档字符串的,它们可能会使阅读代码的人感到困惑。加载文件的顺序很重要。

有些变量仅打算用作局部缓冲区,而有些则是使用的变量defvar-local(或简称为两部分defvar/ make-variable-buffer-local,主要是在添加简写形式之前的较旧代码中使用)。这使得它在所有缓冲区中都是本地缓冲区。对于某些变量,它们的主要用途不是局部于缓冲区,但是由于某些原因,您可能希望一个缓冲区具有不同的值。那是您使用的时间make-local-variable,通常在某些缓冲区设置代码中,几乎不会紧接在defvar。之后。

通常,defvar表单有两个目的。一种是拥有一些文档,以便C-h v其他人可以使用它来了解变量的用途。第二种是声明“默认”值,以便始终设置变量。默认值的声明仅影响变量的全局(或默认)实例,并且仅在该实例尚未设置为某对象时才使用。这意味着,如果您添加了setq一些变量,然后将其包含在文件中defvar(例如,通过require),则defvar将不会更改该值。

¹ 更准确地说,defvar如果变量已经设置,则不要修改它的值(但是它确实设置了文档字符串);这意味着用户的init文件可以(setq some-variable)在加载程序包之前执行以覆盖程序包的默认值。


1
感谢您给出的非常明确的答案,它对您有很大帮助。当我使用“其他文件未知”一词时,我想到的是自由变量警告,因为除非我也向它们添加defvar,否则其他文件会认为该变量是自由的。我喜欢您的声明,该声明set-local告诉读者正在设置本地var。为了提高代码的可读性,我可以做的任何事情都很好!PS。我将尝试更多地点击该资源。在我目前的开发水平上,通常并不能真正理解语义……:-)
凯文(Kevin)

1
defvar每个全局变量只能有一个”并不是严格正确的-在某些情况下,应声明(defvar VARNAME) 值,而与该VARNAME的正确定义(具有初始值和理想的文档字符串)无关。
菲尔斯(Phils)2016年

2
还要注意,setq-local并且defvar-local仅在Emacs 24.3中引入。
菲尔

1
@phils,能否请您确定您所谈论的情况,(defvar varname)应在何处声明值?我想这就是Drew在询问如何摆脱文件中针对我在其他地方声明的全局变量的自由变量警告时在另一个线程中提出的建议。我现在做。您所说的是这种情况吗?
凯文

1
避免字节编译警告是原因之一,是的(请参阅参考资料C-h i g (elisp) Warning Tips)。另一个是使用词法绑定的库,以确保(如有必要)确保变量是动态绑定的,而不是词法绑定的。
菲尔斯(Phils)2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.