我想将参考(指针)保存到我保存在另一个变量中的某些数据的一部分:
(let ((a (list 1 2 3)))
(let ((b (car (cdr a)))) ;here I want to set b to 2, but it is set to a copy of 2
(setf b 4))
a) ;evaluates to (1 2 3) instead of (1 4 2)
我可以使用宏,但是如果我想在列表中间更改一些数据并且我不是很灵活,那么将会有很多代码要执行:
(defparameter *list* (create-some-list-of-arrays))
(macrolet ((a () '(nth 1000 *list*)))
(macrolet ((b () `(aref 100 ,(a))))
;; I would like to change the macro a here if it were possible
;; but then b would mean something different
(setf (b) "Hello")))
是否可以将变量创建为引用而不是副本?
答案 0 :(得分:7)
cl-user> (let ((a '(1 2 3)))
(let ((b (car (cdr a))))
(setf b 4))
a)
;Compiler warnings :
; In an anonymous lambda form: Unused lexical variable B
(1 2 3)
cons
单元格是一对指针。 car
取消引用第一个,cdr
取消引用第二个。你的清单实际上是
a -> [ | ] -> [ | ] -> [ | ] -> NIL
| | |
1 2 3
在您定义b
的地方,(cdr a)
会获得第二个箭头。取car
取消引用第二个单元格的第一个指针并将其值传递给它。在这种情况下,2
。如果要更改该指针的值,则需要setf
而不是其值。
cl-user> (let ((a '(1 2 3)))
(let ((b (cdr a)))
(setf (car b) 4))
a)
(1 4 3)
答案 1 :(得分:4)
如果您只需要一些语法糖,请尝试symbol-macrolet
:
(let ((a (list 1 2 3 4)))
(symbol-macrolet ((b (car (cdr a))))
(format t "~&Old: ~S~%" b)
(setf b 'hello)
(format t "~&New: ~S~%" b)))
请注意,这绝对是编译时的事情。在symbol-macrolet
的范围内,b
用作变量,它在编译时扩展为(car (cdr a))
。正如Sylwester所说,Common Lisp中没有“引用”。
但我不推荐这种做法用于一般用途。
顺便说一下:永远不要改变引用的数据。在(setf (car ...) ...)
这样的常量列表文字上使用'(1 2 3)
(和类似的)会产生不明确的后果。
答案 2 :(得分:1)
以Baggers的建议为基础。不完全是您正在寻找的,但您可以定义setf-expanders来创建访问者'。因此,假设您的列表包含有关(名字姓氏军事状态)的人员的信息,当有人结婚时,您可以将其更新为:
(defun marital-status (person)
(third person))
(defun (setf marital-status) (value person)
(setf (third person) value))
(let ((person (list "John" "Doe" "Single")))
(setf (marital-status person) "Married")
person)
;; => ("John" "Doe" "Married")