CLOS插槽访问器:读取但不写入

时间:2014-06-20 20:20:55

标签: lisp common-lisp accessor slot clos

我有一个CLOS对象的插槽名称列表:

(DEFCLASS TRIAL-DATA (STANDARD-OBJECT) 
 ((A-DATUM :ACCESSOR A-DATUM :INITARG :A-DATUM :INITFORM NIL) 
  (BOTH-DATA :ACCESSOR BOTH-DATA :INITARG :BOTH-DATA :INITFORM 0) 
  (CUMULATIVE-DATA :ACCESSOR CUMULATIVE-DATA :INITARG :CUMULATIVE-DATA :INITFORM NIL) 
  (NAME :ACCESSOR NAME :INITARG :NAME :INITFORM VALUE)))

(let* ((td (make-instance 'trial-data))
   (slot-lst (mapcar #'slot-definition-name (class-slots (class-of td)))))

我可以读取这些插槽的值:

(let* ((td (make-instance 'trial-data))
   (slot-lst (mapcar #'slot-definition-name (class-slots (class-of td)))))
(funcall (symbol-function (nth 0 slot-lst)) td))

==> NIL

但为什么我不能为这些插槽写新值?我的类试验数据定义是否应该为每个插槽创建一个访问函数?

;; Should set the first slot, a-datum's, value to 42
(let* ((td (make-instance 'trial-data))
       (slot-lst (mapcar #'slot-definition-name (class-slots (class-of td)))))
    (setf (funcall (symbol-function (nth 0 slot-lst)) td) 42))

==>

;Compiler warnings for "/Users/frank/Documents/NRL/Error/Patrolbot/Patrol Construction Notes & Testing.lisp" :
;   In an anonymous lambda form at position 123: Undefined function (SETF FUNCALL)
> Error: Undefined function (SETF FUNCALL) called with arguments (42 #<STANDARD-GENERIC-FUNCTION A-DATUM #x302001D1C5DF> #<TRIAL-DATA #x30200200D95D>) .
> While executing: #<Anonymous Function #x30200200EB7F>, in process Listener-2(5).

2 个答案:

答案 0 :(得分:5)

访问者称为a-datum

读者:

CL-USER 9 > #'a-datum
#<STANDARD-GENERIC-FUNCTION A-DATUM 406000091C>

作者:

CL-USER 10 > #'(setf a-datum)
#<STANDARD-GENERIC-FUNCTION (SETF A-DATUM) 422000958C>

如果您想通过作家funcall致电,则需要调用上述功能。

如果你有一个简单的格式(setf (a-datum foo) 'bar)),那么这需要在宏扩展时解决。

错误消息显示#'(setf funcall)未定义。因此(setf (funcall ...) ...)不存在。

如何在你的情况下获得作家功能?

CL-USER 11 > (fdefinition '(setf a-datum))
#<STANDARD-GENERIC-FUNCTION (SETF A-DATUM) 422000958C>

CL-USER 12 > (let ((name 'a-datum)) (fdefinition `(setf ,name)))
#<STANDARD-GENERIC-FUNCTION (SETF A-DATUM) 422000958C>

任务:上述函数的正确参数是什么?

答案 1 :(得分:2)

Rainer Joswigs's answer解决了您无法使用现有代码进行设置的问题。但是,同样重要的是要注意,读者,作者或访问者名称没有理由与插槽名称相同,所以如果您实际获得的是插槽名称,那么您应该使用{{1} } 用它。例如,

(setf slot-value)
(defclass foo ()
  ((bar :accessor getbar :initform 42)))

(defparameter *foo* (make-instance 'foo))