如何执行上SETF地方的功能

问题描述 投票:1回答:3

我有一个包含一些符号和值的列表。我们的目标是与存取,其符号由列表提供给SETF类的插槽:

(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-slotswith-accessors但问题仍然是相同的,因为他们太宏。
  • 我已经考虑它声明等宏观和符号macrolet太宏。

我怎样才能通过相应的在我的列表中的符号的访问SETF插槽?

谢谢。

common-lisp setter clos setf
3个回答
3
投票

调用存取函数

我们的目标是与访问到SETF类插槽

存取器是一个双功能。你可以得到这台通过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被设计为动态和反思,让这些东西。


2
投票

您可以使用setfslot-value,采用槽名称符号在你的数据对:

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

然而,直接使用slot-value通常唯一明智的,当你在对象内部争吵(如初始化实例方法/组合;或者你正在研究一些序列化机制)。

如果不是的话,你正在使用的对象只是作为一个关联数据结构。我建议使用ALIST,plist中,或哈希地图代替。


1
投票

我认为,像hash-table另一种结构可能应该使用。但为了扩大有关Svante's slot-value答案,工作代码很简单:

(setf (slot-value obj 'attr) "some-value")
© www.soinside.com 2019 - 2024. All rights reserved.