emacs如何定义一个常量,setq也无法修改的那种

defconst 定义的 setq还是能修改。

不能zsbd

用closure或许能模拟常量,但是对于复合数据类型来说,还是可以修改内部结构

(defalias 'really-constant-var
    (let ((x (list 1 2 3)))
      (lambda () x)))

(really-constant-var)
;; => (1 2 3)

(setf (car (really-constant-var)) 3)
;; => 3

(really-constant-var)
;; => (3 2 3)

常量应该是在编译期确定/约束的,执行期在内存里怎么样都可以修改的。常见的动态语言里都没有常量这一概念吧。

26.1 之后可以这样:

(defvar const-var t)

(add-variable-watcher 'const-var #'const-var-watcher)

(defun const-var-watcher (sym _newval _op _where)
  (error "assignment of read-only variable ‘%s’" sym))

(setq const-var nil) ;; error
2 个赞
(defvar const-var t)

(add-variable-watcher 'const-var #'const-var-watcher)

(defun const-var-watcher (sym _newval _op _where)
  (error "assignment of read-only variable ‘%s’" sym))

(defvaralias 'alias-to-const-var 'const-var)
;; Error ???

可以先加一个判断

参数 op 可以区分操作类型是 set 还是 defvaralias

不想报错,就是想 setq 修改这个变量无效,还是原来的值。最多 warning 提示一下。用下面的好像并没有效果。

(defvar const-var t)
(add-variable-watcher 'const-var #'const-var-watcher)
(defun const-var-watcher (sym _newval _op _where)
  (when (string= "set" _op)
    (remove-variable-watcher 'package-archives #'const-var-watcher)
    (setq const-var t)
    (add-variable-watcher 'package-archives #'const-var-watcher)
    ;; (error "assignment of read-only variable ‘%s’" _op)
    ))

(setq const-var nil)

想要 const 又不报错。

就像是 try...catch 不处理,也不往上抛,静悄悄把问题掩盖起来。

本来 assign to constant在byte-compile时就会报warning啊??

warning 只是附带,可有可无的,主要是setq 修改不要起作用。

本来想重新定义 setq ,定义一个列表包含所有不想被修改的变量,然后 setq 先判断变量是否在上面的列表内,然后分别处理,弄了两个多小时没弄出来。大神帮我看看。

(defvar var-list '())
(defmacro setq (&rest settings)
  `(progn
     ,@(cl-loop for (var val) on settings by 'cddr
                unless (member var var-list)
                collect `(funcall #'set ',var ,val)
                )))

不用 setq 命名这个宏,可以用。但是用 setq 命名的话,cl-loop 里也调用 setq 导致超出限制了。

我研究一下 try…catch

警告就改成:

(defun const-var-watcher (sym _newval _op _where)
  (warn "assignment of read-only variable ‘%s’" sym))

我还是认为,既然是 const,就该报错。及早从源头杜绝错误,而不是把错误隐藏起来。

我是想在 site-start.el 里把 package-archives 里写死(还有其他一些变量).这样用其他的 emacs 配置就不用一个个设置了. warn 不能阻止修改值。

你前面知道改回去,这么快就忘了?

这个嘛,这个我试了没效果。

你说的 try…catch 应该可以,我查查。

请直接问这个问题. 不然别人会以为你在Elisp编程的时候出现了需要严格constant做约束的场景. (事实上你只是希望对不同配置pin一个变量)

答案是不能, 请自己分别找一下各个配置里允许你改package-archives的地方改上.(或许可以用prin1之类的东西批量生成)

  1. 这样改没啥用, setq并非set语法糖. setq可以修改词法作用域的变量,set则是专门用来修改全局变量的. 你用宏魔改setq,会破坏setq的语义,可能导致emacs整个都坏掉.

  2. 对于编译的配置(比如doom) setq在编译时已经变成字节码, 再捣鼓setq宏也不会有任何作用.

(byte-compile '(setq a 1))
;; => (byte-code "\301\211\207" [a 1] 2)

用宏改确实有问题,都不能启动了。直接改C代码的 setq 可以用了。 主要是 spacemacs 自己定义的很多变量,懒得看。 感谢各位。