gv-define-setter
只能用来定义基础的 setter 函数,类似于 car/setcar
, aref/aset
之类的。如果 name
对应的 getter 函数接受了 gv
参数它是不能正常工作的。
具体原因可见源代码:gv-define-setter
内部调用了 gv--defsetter
,gv--defsetter
展开过程中会使用 macroexp-let2
来保证 setter
函数将要应用到的参数们只被求值一次。
(defun gv--defsetter (name setter do args &optional vars)
"Helper function used by code generated by `gv-define-setter'.
NAME is the name of the getter function.
SETTER is a function that generates the code for the setter.
NAME accept ARGS as arguments and SETTER accepts (NEWVAL . ARGS).
VARS is used internally for recursive calls."
(if (null args)
(let ((vars (nreverse vars)))
(funcall do `(,name ,@vars) (lambda (v) (apply setter v vars))))
;; FIXME: Often it would be OK to skip this `let', but in general,
;; `do' may have all kinds of side-effects.
(macroexp-let2 nil v (car args)
(gv--defsetter name setter do (cdr args) (cons v vars)))))
这样,参数表里面的 gv
参数的值就直接保存到了局部变量中,就不知道它对应的 setter
函数相关信息了。(你的代码中的 gv
变量就是 integer
,它的 setter form 是 (setq integer …),但是这个没法得到。
上面的解决方案中使用了 gv-letplace
从 gv
参数中获取到了 getter
和 setter
表达式,从而能够正常工作。