我有一个包含一些符号和值的列表。目的是通过访问器设置类插槽,访问器的符号由列表提供:
(defclass my-class ()
((attr :accessor attr)))
(let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(setf `(,(car to-call) obj) (cadr to-call)))
我已经通过宏进行了尝试:
(defmacro call-accessor (to-call)
`(setf (,(car to-call) obj) "some-value"))
(let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(call-accessor to-call))
这也是失败的,因为to-call
是符号而不是列表。
eval
不起作用,因为to-call
是一个词法变量; let
来为其提供列表; with-slots
和with-accessors
,但是问题仍然存在,因为它们也是宏。如何通过与列表中的符号相对应的访问器设置插槽?
谢谢。
答案 0 :(得分:3)
调用访问器功能
目标是通过访问器设置类插槽
访问器是一对功能。您可以通过FDEFINITION
获取设置值的部件。函数的名称是列表(SETF accessor-name )
。这很不寻常:Common Lisp在这种情况下具有的函数名称不是符号,而是列表。
CL-USER 14 > (let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(funcall (fdefinition `(setf ,(first to-call)))
(second to-call)
obj)
(describe obj))
#<MY-CLASS 40200614FB> is a MY-CLASS
ATTR "some-value"
使用功能call-accessor
:
CL-USER 25 > (let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(flet ((call-accessor (obj to-call)
(funcall (fdefinition `(setf ,(first to-call)))
(second to-call)
obj)))
(call-accessor obj to-call)
(describe obj)))
#<MY-CLASS 402000220B> is a MY-CLASS
ATTR "some-value"
使用SETF和APPLY来隐藏FDEFINITION调用
要将setf
与计算访问器一起使用,可能需要使用apply
形式和自定义函数。
像call-accessor
之类的东西自然是一个函数,因为它执行运行时查找并获取值。如果在编译时知道访问器,则尝试使用宏将更为有用。
CL-USER 23 > (let ((to-call '(attr "some-value"))
(obj (make-instance 'my-class)))
(flet (((setf my-setter) (new-value object accessor)
(funcall (fdefinition `(setf ,accessor))
new-value
obj)))
(flet ((call-accessor (obj to-call)
(setf (apply #'my-setter obj (list (first to-call)))
(second to-call))))
(call-accessor obj to-call)
(describe obj))))
#<MY-CLASS 40200009AB> is a MY-CLASS
ATTR "some-value"
选择数据结构
我认为可以计算访问器函数和类似函数。可能会有用例。 CLOS被设计为动态的和反射性的,以允许这些事情。
答案 1 :(得分:2)
您可以在数据对中使用插槽名称符号来使用slot-value
中的setf
:
(let ((to-call '(attr "some-value")))
(setf (slot-value obj (first to-call)) (second to-call)))
但是,通常只有在处理对象内部问题时才明智地直接使用slot-value
(例如initialize-instance方法/组合;或者您正在研究某种序列化机制)。
如果不是这种情况,则您将对象用作关联数据结构。我建议改用alist,plist或hash-map。
答案 2 :(得分:1)
我同意应该使用hash-table
之类的替代结构。但是要扩展关于slot-value
的{{3}}答案,工作代码很简单:
(setf (slot-value obj 'attr) "some-value")