应该尽量使用setq还是setq-default?

我还是在纠结这个问题:什么情况下必须使用setq-default?

那么对那些既能使用setq,也能使用setq-default的var来说,应该尽量使用setq还是setq-default

谢谢各位

1 个赞

setqsetq-default 作用不一样,不存在「应该尽量用哪个」这种情况,需要用哪个就用哪个。

普通的变量只要一个值,setq-default 没有意义,应该直接用 setq

对于 buffer local 变量,这样的变量每一个 Buffer 都有一个独立的值,因为不是每一个 buffer 都主动会设置它,所以需要有一个「初始值」或者「默认值」或者「全局值」,创建新 buffer 会自动继承这个值,如果需要修改这个「默认值」就只能用 setq-default;如果需要修改这个变量在当前 buffer的值就只能用 setq。所以当使用 (setq-default foo ...) 时,你确认

  1. foo 是个 buffer-local 变量
  2. 你想修改 foo 的「默认值」
1 个赞

普通的变量会变成 buffer-local 变量,当你用 defvar-local / make-local-variable / setq-local 时。

谢谢。

我看到有些配置里会对不是buffer-local的变量也使用setq-default。所以产生了以前那个以及这个问题。

另外file-local变量是不是buffer-local变量?换句话说我怎么判断一个变量是不是buffer-local的?看docstring吗?

让我在意这点的是 https://www.gnu.org/software/emacs/manual/html_node/elisp/Default-Value.html 里的一段话:

For example, you could use setq-default to change the default setting of paragraph-start for most buffers; and this would work even when you are in a C or Lisp mode buffer that has a buffer-local value for this variable.

我从哪儿也没看出来 paragraph-start 是个buffer-local变量啊……

看源码 写代码

而不是

想代码 写代码

这得看是在哪个 buffer 中,C、Org 模式的 buffer 中 paragraph-start 是 buffer-local 的,其它 buffer 中它不是 buffer-local 的。

有些变量譬如 tab-widthmode-line-format 的 docstring 会提示

Automatically becomes buffer-local when set.

这不是说 tab-width 是个 buffer-local 变量,是不是 buffer-local 需要首先指明哪个 buffer 才有意义,

回到你的问题,某个 buffer 中

  • 假设 paragraph-start 不是 buffer-local 的,setqsetq-default 效果相同,修改全局值;
  • 假设 paragraph-start 是 buffer-local 的,setq 修改这个 buffer-local 值,setq-default 修改全局值;

所以我的迷茫点也在此处……就是我要的到底是什么。

以及如果在该使用setq的时候使用了setq-default,可能会造成什么影响?

我能预见的就是我将会设置一个本来不该设置的默认值,然后就各种乱套……

自然就是可能达不到你想要的目的呗

下次等你遇到了具体的例子再谈论更好些。

事实上我遇到的都是一些“模棱两可”的变量, 比如magit-diff-refine-hunk, smex-history-length, smex-save-file这类的,我见过有人用setq, 也见过有人用setq-default……

可能两者都是对的,用哪一个取决于你想达到的目的(或者需要强调的内容)。不是说一个变量就只能用(或最好用) setq,而不能也用(或最好不用)setq-default,或者反过来。

这个例子很好,因为我也设置了它(大致如下[1]),我想修改它的值,而我的用法是错误的

(with-eval-after-load "magit"
  (setq magit-diff-refine-hunk t))

正确的选择是 setq-default,上面的代码没有考虑过 buffer-local 的情况,只是 setq 出问题条件比较苛刻:

  • 第一次使用 Magit 时所在的 Buffer 设置了已经设置 magit-diff-refine-hunk 的 buffer-local 值,一般是通过 File / Directory local variable。

如果你的 init.el 像下面这样写,同样是 setq 却不会有问题,因为它没有机会满足上面的条件

(require 'magit)
(setq magit-diff-refine-hunk t)

只是为了强调 magit-diff-refine-hunk 有时会是 buffer-local 的,而你想设置默认值,可以用 setq-default


[1] 我的 Magit 的全部设置如下(相关的设置等价于上面第一段代码)

1 个赞
  • package-archivessetq 没什么好说的,这个变量不存在 buffer-local 的情况;
  • mode-line-format 这种变量「Automatically becomes buffer-local when set.」,如果用户需要设置一个公共的 Mode Line,就得用 setq-default
  • magit-diff-refine-hunk 这种变量偶尔作为 buffer-local,当它不是 buffer-local 时,setqsetq-default 效果相同,都是修改默认值;当它是 buffer-local 时,setq-default 设置默认值,setq 设置 buffer-local 值
1 个赞

看到这里你这个帖子比我刚看到它时的意义多了那么一点点,不是”完全没什么好讨论的”了。不过很显然你对这两个有了基本的了解之后,用出问题的可能就非常小了,这时候再使劲想什么edge case下应该怎么用,只是过度、过早优化。因为它俩只是工具,也不会帮你提高elisp水平什么的。

他应该较真儿的是buffer local的实现