如何使用字符串访问未知实例的插槽?

时间:2014-10-07 20:53:35

标签: lisp common-lisp symbols slots clos

问题

给定instanceinst和包含slot名称的字符串attr,如何获取广告位attr的值inst

当然,如果attr是符号而不是字符串,我通常会使用(slot-value inst 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的{} - 格式化。要实现Python .运算符(getattr),我需要转换 将点后面的字符串插入点之前的对象上的插槽中。

1 个答案:

答案 0 :(得分:3)

  

给定一个实例,inst和一个包含插槽名称的字符串attr,如何在inst上获取slot 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