2014-10-07 61 views
2

問題

給定一個instanceinst和含有slot的名稱的字符串attr,我怎樣才能獲得時隙attrinst的值?如何使用字符串訪問未知實例的插槽?

當然,如果attr是一個符號而不是字符串,我通常只使用​​,但似乎我需要包信息才能正確調用intern(請參見下文)。

最小示例

(defpackage :pack1 
    (:use :common-lisp) 
    (:export :*inst*)) 

(in-package :pack1) 

(defclass temp-class() 
    ((temp-slot :initarg :temp-slot))) 

(defvar *inst* (make-instance 'temp-class :temp-slot "value")) 

(defpackage :pack2 
    (:use :common-lisp :pack1) 
    (:import-from :pack1 :temp-class)) 

(in-package :pack2) 

(let ((inst *inst*) ; In the real example, inst gets defined outside my control, 
        ; in yet another package 
     (attr "temp-slot")) 
    (format t "Given package name: ~S; " ; prints fine 
      (slot-value inst (intern (string-upcase attr) :pack1))) 
    (format t "No package name: ~S; " ; signals an error 
      (slot-value inst (intern (string-upcase attr))))) 

現有技術

  • this question,我想通了,我的問題是,intern被創建在不同的包比在其定義的類中的一個符號。
  • 似乎從this question,我不能簡單地從實例中提取的包信息,所以我必須找出另一種方式(除了使用intern到那裏)

背景

我正在研究py-format一個Common Lisp端口 Python的{} -formatting。要實現Python .運算符(getattr),我需要將點後面的 字符串轉換爲點之前的對象上的插槽。

回答

3

給定一個實例,瞬時和包含槽的名稱的字符串ATTR,我怎麼能獲得出師表插槽attr的價值?

插槽沒有字符串作爲插槽名稱,但符號。由於插槽名稱可以是任意符號,因此如果您只有一個字符串,則沒有通用的方法來獲取插槽值。

CL-USER 124 > (defclass foo() 
       ((s)    ; the slot-name is cl-user::s 
       (system::s)  ; the slot-name is system::s 
       (#:s)))   ; the slot-name is  #:s 
#<STANDARD-CLASS FOO 413054236B> 

最後的插槽名稱是未插入的符號。它沒有包裝。 因此,你不能以任何方式查找它,如果你還沒有存儲它的地方。

CL-USER 125 > (make-instance 'foo) 
#<FOO 402013F043> 

CL-USER 126 > (describe *) 

#<FOO 402013F043> is a FOO 
S  #<unbound slot> 
S  #<unbound slot> 
S  #<unbound slot> 

如上所示,它有三個插槽。每個符號都有名稱s,但實際上是一個不同的符號。

您可以通過內省得到插槽名稱:

CL-USER 127 > (mapcar #'slot-definition-name 
         (class-direct-slots (find-class 'foo))) 
(S SYSTEM::S #:S) 

對於便攜式功能看CLOSER-MOP

+0

謝謝 - 最後一點自省將幫助我重新思考語法 – Felipe 2014-10-07 21:26:21