你为什么不摆脱 set-global
函数完全,如果您希望所有功能都具有在全局变量中具有相同风格的传递样式,则只需使它们全部使用 symbol-value
因此,任何使用这些功能的人都不需要知道哪个dik和哪个不需要在全局变量名称之前的报价。更容易吧?
题
更新:如果我有一些函数,我想突变一个作为函数参数传递的全局变量,则有些可以通过仅传递全局的符号来做到这一点(如将某物推到列表的一部分的情况下) ,但是其他功能将要求在传递时引用该符号,以便我可以访问符号值并突变外部变量,这是在函数中使用setQ所需的。这个问题基本上是关于为这些功能的用户创建一个一致的界面,而不会使它们混淆,有时您会传递符号,其他时间是您传递的符号
通过使用具有相同用法的助手对突变函数的工作方式进行相同的用法,简化界面的界面方法:
这是我技术的两个基本示例:
(defun push-something (global something)
(push something global)
global) ;; not necessary to return it here since the
;; preceding line already does, but doing so
;; for consistency with other functions and clarity
(defun push-cdr (global something)
(push something (cdr global))
global) ;; must return it if I am going to set the
;; dynamic var to the result of this function,
;; because the preceding line doesn't return the
;; entire new result of the variable
;;; "dirty" function for mutating global variable using "clean" functions above:
(defun set-global (fn global &rest values)
(setf (symbol-value global) (apply fn (copy-list (eval global)) values)))
在最后一个,我必须 eval
这 global
由于它被引用用于 symbol-value
然后我 copy-list
以便 global
任何东西都不会直接突变 fn
我选择(就像 push-cdr
在更复杂的功能中可能是不平凡的)。
输出:
CL-USER> (defparameter *g2* nil)
*G2*
CL-USER> (set-global #'push-something '*g2* 5)
(5)
CL-USER> *g2*
(5)
CL-USER> (set-global #'push-cdr '*g2* 99)
(5 99)
CL-USER> *g2*
(5 99)
...并且可以使用相同的功能 *g1*
或者 *g3*
等等通过访问功能 set-global
.
这是好还是坏的风格,还是我错过了实现此功能的更好方法?
解决方案 2
其他提示
这是一种糟糕的风格,浪费了您的时间。
push-something
等同于cons
.push-cdr
是 不是 函数:它可以在现场修改参数或失败,并在错误上发生错误nil
争论。
如果要更改全局变量的值,则使用 setf
明确清楚得多。
如果您想以某种复杂的方式修改全局值的内部,则可能需要为此编写一个特殊的功能 - 但是该功能应该不可知,因为它正在修改与全局变量绑定的值的事实词汇变量。
简而言之,有两个单独的正交问题 - 更改全局变量(使用 setq
)并改变对象的内部(不可知其全球性质)。
PS。我不确定您的意思是“ setf在函数内部不更改全局变量的值”,但是:
(defvar *foo* 10)
*FOO* ==> 10
(defun change-foo (x) (setq *foo* x))
(change-foo 123)
*foo* ==> 123
不隶属于 StackOverflow