2014-06-20 33 views
0

我有一個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)) 

== >無

但爲什麼我不能向這些插槽寫入新值?我的班級定義的試用數據是否應該爲每個插槽創建一個訪問函數?

;; 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

Rainer Joswigs's answer解決了您無法使用現在的代碼進行設置的問題。但是,請注意,讀者,作者或訪問者名稱沒有必要與插槽名稱相同的原因也很重要,因此如果您實際得到的是插槽名稱,那麼您應該使用(setf slot-value)。例如,

(defclass foo() 
    ((bar :accessor getbar :initform 42))) 

(defparameter *foo* (make-instance 'foo)) 
;; neither of these work 
(setf (bar *foo*) 34) 
(funcall #'(setf bar) 34 *foo*) 

(slot-value *foo* 'bar) 
;=> 42 

(setf (slot-value *foo* 'bar) 36) 
;=> 26 

(slot-value *foo* 'bar) 
;=> 36 
+0

所以,你可以用'(mapcar#'插槽定義名稱(類插槽(TD類的)))'和'(SETF插槽值)一起'並通過索引讀取/寫入插槽的數據。 – Mark

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> 

任務爲你:以上功能的正確參數是什麼?