如题. 可能还有其它易混淆的赋值方式没列举出来.
设定 user option 应该用 setq, setopt, custom-set-default, customize-set-value, 还是 customize-set-variable?
我在 :config 里用 setq,速度最快
但是存在一些情况 setq 无法正确设置值(比如这个变量在加载包的 defvar 的时候被另一个变量引用了)我会设置成在 :init 里面使用 setq
(手机打字,某些函数名可能不太对)
setq 是最直接的,它跳过了 option 的变量类型检查和设置函数
setopt 会使用 option 的设置函数,内部貌似是调用 custom-set-variable
customize-set 之类的函数应该是最“正规”的方法?emacs会在你使用那个设置界面时使用它设定option
就我来看的话,在 emacs 29 中,如果你想要把某些 option 设定写死在配置文件中,就使用 setopt吧,我一般把它放到 use-package 里面的 init,其他通过 customize 界面配置的 option 放在自动生成的代码里就行
但是也并不一定,我遇到过 option 类型与正确值冲突的问题,这时候 setopt 可能不太好用,这时候用setq就行
- 包加载之前用defvar
- 包加载之后,如果是plain variable用setq,如果是有set函数的variable,用setopt
- 或者全无脑在init阶段用setopt
别的api语法有点复杂,我个人基本不用
custom-set-default
不是给用户用来设定变量用的,而是给 defcustom
用的 :set
选项的默认值。
customize-set-value
和 customize-set-variable
是用来 M-x
交互式调用的,提供当前 defcustom
变量的䃼全。后者会用 custom-set
,前者不会。
setopt
才是设计用在配置代码里做少量修改的。有 custom-set
时用优先用它,没有就用 set-default
,是没有加載变量对应的包时也要使变量生效时用的。它不会去主动 require 对应的包。
setq
现在有编译时对变量是否定义的檢查,不在意的话无所谓,在意就用 setq-default
,这个也能全局设定 buffer local variable。setq
在 byte code 里有专门的指令,而 setq-default
只会展开成对 set-default
的 funcall。setq-local
一般不用在配置选项里,不提
custom-set-variables
才是用来让用户批量设置 defcustom
的,等价于 (custom-theme-set-variables 'user ...)
,后者顾名思意是给 theme 用的。和 setopt
区別是只有在对应的 defcustom
加載时才会生效,确保调用的是正确的 custom-set
。
use-package
如果 :config
和 :defer t
一起用,那就等于 eval-after-load
,:ensure t
时
:config
等价于 :init
。:custom
用的是 (custom-theme-set-variables ʻuse-package ...)
。
Emacs 的 theme 不只管理 face,也能管理 defcustom,而且能同时打开以组合多个 theme,也能在关闭 theme 时正确重置变量。用 setq/setopt 就没有这个好处了。
看了一下 GNU 的 Emacs Lisp Reference Manual,也提到了这点:
The main use case for this macro is setting user options in the user’s init file.
但感觉即使 setopt
有会保证 option 的 setter function 被执行并且会检查 option 被设定值的合法性(类型是否匹配等)的优点,大部分人的 .emacs.d 还是用的 setq
。
In particular,
setopt
will run the setter function associated with the variable.
setopt
also checks whether the value is valid for the user option. For instance, usingsetopt
to set a user option defined with anumber
type to a string will signal an error.
话说这里的 less efficient 指的是哪些方面?
The
setopt
macro can be used on regular, non-user option variables, but is much less efficient thansetq
.
Emacs 29 才有这个宏,没普及很正常,以至于 buffer local variable 到 25 才有。 而且大部分变量没有特殊的 custom-set 属性,即设置之后要另外调用函数才能完全生效。
更何况不编译的话 setq 是解释器直接支持的 special form,setopt 还要宏展开。
个人习惯,写在个人配置代码里的几乎都是用 setq。事实上,如果你在加载一个包之前就 setq 这个包里定义的变量,那么 custom 对应的 setter 函数也能够顺利执行。但是如果你在加载这个包之前就 setq,那么这个变量在后期就不能被动态绑定(比如在 let 里面绑定这个变量到另一个值)。只有在需要动态绑定这个变量(因此你必须要在加载这个包之后才设置这个变量),同时这个变量还有对应的 setter 函数,这个时候才有必要使用 setopt,我很少很少遇到过这种情况。
至于 custom-***
是不会出现在我的配置里的。
只要在 setq 之前 defvar
就行。当然,实际上 defvar
只要在 closure variable capture 之前出现就没有问题,不能动态绑定本质上是代码不规范没有在使用动态作用域变量之前 require
其对应的 defvar
所在的文件或另外声明 defvar
导致的。
额外附一条说明,在变量本身 unbound 的情況下,用不带 initvalue 的 defvar
不会给变量赋值,见 为啥一个无关的局部绑定会引起编译警告?
如果没有对应的 setter,在动态绑定行为上 setopt
的行为和 setq
和 setq-default
都是一样的,并不会自动让变量变 special,所以你的说法是不准确的。
需要包加载完以后改 custotm 变量,或包的加载状态不固定如 pdumper 和 lazy 都在用的情况还是有的。
(用custom可以带备注
你这个人看起来对elisp好精通啊,我也是搞不清楚 啥子时候用setq setq-default 来搜索,看到这个帖子了