如何在 setf 地方执行一个函数

How to execute a function on setf place

我有一个包含一些符号和值的列表。目标是使用访问器设置 class 插槽,其符号由列表提供:

(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 是一个符号而不是列表。

如何通过与我的列表中的符号对应的访问器设置插槽?

谢谢。

您可以使用 setf of slot-value,使用数据对中的插槽名称符号:

(let ((to-call '(attr "some-value")))
  (setf (slot-value obj (first to-call)) (second to-call)))

然而,直接使用 slot-value 通常只在你争论对象内部时才有意义(比如初始化实例 methods/combinations;或者你可能正在研究某种序列化机制)。

如果不是这种情况,则您只是将该对象用作关联数据结构。我建议改用 alist、plist 或 hash-map。

我同意可能应该使用 hash-table 之类的替代结构。但是要扩展 关于 slot-value 的答案,工作代码很简单:

(setf (slot-value obj 'attr) "some-value")

调用存取函数

The goal is to setf the class slot with the accessor

访问器是一对函数。您可以通过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 被设计成动态的和反射的以允许这些事情。