我想知道如何在函数内部永久地改变全局变量的值,而不在函数内使用变量的名称,即:
(defvar *test1* 5)
(defun inctest (x) (incf x))
(inctest *test1*) ;after it runs, *test1* is still 5, not 6
根据this:
如果传递给函数的对象是可变的并且您在函数中更改它,则调用者将看到更改,因为调用者和被调用者都将引用相同的对象。
这不是我上面做的吗?
答案 0 :(得分:2)
你没有做引用所说的内容,即改变传递给你的函数的对象。您正在改变参数x
,即函数的局部变量,其中包含对象的副本。
要执行引用所说的内容,您需要一个实际上可变的对象,而不是数字的情况。如果您使用可变对象,例如列表,它的工作原理:
(defvar *test2* (list 5))
(defun inctest2 (x) (incf (car x)))
(inctest2 *test2*)
*test2* ; => (6)
答案 1 :(得分:1)
如果您希望inctest
成为一个函数,请将全局变量的名称传递给它。
(defun inctest (x) (incf (symbol-value x)))
(inctest '*test1*)
答案 2 :(得分:1)
在便携式Common Lisp中,没有明确的"指针"并且所有参数都按值传递。为了能够传递一个函数,你需要修改一个变量所需的变量。
如果变量是全局变量,那么您可以使用变量的名称(symbol
),然后使用symbol-value
来读/写变量:
(defvar *test1* 42)
(defun inctest (varname)
(incf (symbol-value varname)))
(inctest '*test1*) ;; Note we're passing the NAME of the variable
如果相反变量是本地的,你可以提供一个闭包,当没有参数调用时返回当前值,而当用参数调用时,它将设置变量的新值:
(defun inctest (accessor)
(funcall accessor (1+ (funcall accessor))))
(let ((x 42))
(inctest (lambda (&optional (value nil value-passed))
(if value-passed
(setf x value)
x)))
(print x))
您还可以编写一个小助手来构建访问者:
(defmacro accessor (name)
(let ((value (gensym))
(value-passed (gensym)))
`(lambda (&optional (,value nil ,value-passed))
(if ,value-passed
(setf ,name ,value)
,name))))
之后代码变为
(let ((x 42))
(inctest (accessor x))
(print x))
答案 3 :(得分:0)
不,它会更改您提供的副本。
要更改变量本身,请使用其名称在函数体中更改它:
(incf *test1*)
编辑:如果你接受了宏,就在这里,从我的粘液中滚烫:
(defmacro my-incf (variable-name)
`(incf ,variable-name))