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

Fel*_*ipe 4 lisp symbols common-lisp clos slots

问题

给定一个实例和一个包含插槽名称的inst字符串,如何获取插槽的值?attrattrinst

当然,如果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)))))
Run Code Online (Sandbox Code Playgroud)

现有技术

  • 这个问题中,我发现我的问题是intern在与定义类的包不同的包中创建符号。
  • 从这个问题看来,我无法简单地从实例中提取包信息,所以我必须找出另一种方法(除了使用intern来到达那里)

背景

我正在研究py-formatPython 格式化的 Common Lisp 端口{}。要实现 Python.运算符 ( getattr),我需要将点后面的字符串转换为点前面的对象上的槽。

Rai*_*wig 5

给定一个实例、inst 和一个包含插槽名称的字符串 attr,如何获取 inst 上插槽 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>
Run Code Online (Sandbox Code Playgroud)

最后一个插槽名称是一个未驻留的符号。它没有包装。因此,如果您没有将其存储在某个地方,您就无法以任何方式查找它。

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>
Run Code Online (Sandbox Code Playgroud)

正如您在上面看到的,它有三个插槽。每个符号都有名称s,但实际上是不同的符号。

您可以通过自省获取插槽名称:

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

对于便携式功能,请参阅CLOSER-MOP