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

问题描述 投票:0回答:1

问题

给定一个instance

inst
和一个包含
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)))))

现有技术

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

背景

我正在开发

py-format
的 Common Lisp 端口 Python 的
{}
格式。要实现 Python
.
运算符 (
getattr
),我需要将 点后面的字符串插入点前面的对象上的槽中。

lisp common-lisp symbols slots clos
1个回答
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>

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

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

© www.soinside.com 2019 - 2024. All rights reserved.