【问题标题】:How to access metaobjects/slot-definition slots? Why slot-value can access slots of objects but not slots of metaobjects?如何访问元对象/槽定义槽?为什么 slot-value 可以访问对象的插槽而不是元对象的插槽?
【发布时间】:2019-07-08 23:00:04
【问题描述】:

我在访问插槽定义之外的插槽时遇到问题。我可以检查类对象,查看它们的槽定义,甚至获得一些关于槽定义的标准信息。但是我无法访问有关插槽定义的用户定义信息。

我已经在谷歌上搜索了很长一段时间,最后阅读了CLOS & MOP specifications,一些Lisp Cookbook,一些MOP concepts,和somerelatedquestionson StackOverflow没有太大帮助。我什至读了一篇SBCL's implementations,但无济于事。

从我能够组合在一起的部分中,我可以通过某些功能访问SLOT DEFINITION 的许多插槽,例如使用CLOSER-MOP:SLOT-DEFINITION-NAME 访问SLOT DEFINITIONNAME 插槽(这当然很有帮助),但对于没有这些功能之一的插槽,我不能这样做。例如,在DEFCLASS 中定义插槽时,我无法访问MITO 包提供的REFERENCES 插槽。

这是一个最小的工作示例:

(load "~/quicklisp/setup.lisp")
;;;; I'll use MITO because its classes have a funny REFERENCES slot
(quicklisp:quickload :mito)
;;;; I find CLOSER-MOP functions easier to use than
;;;; implementation-specific functions
(quicklisp:quickload :closer-mop)


;;;; Creates a few dummy classes
(defclass example ()
  ((one-slot :col-type (:varchar 50)
             :accessor one-slot-accessor))
  (:metaclass mito:dao-table-class)
  (:documentation "An example class."))

(defclass another-example ()
  ((normal-slot :col-type (:varchar 50)
                :accessor normal-slot-accessor)
   (example-reference :references (example id)
                      :reader example-reference-accessor))
  (:metaclass mito:dao-table-class)
  (:documentation "Another example class which references `EXAMPLE' class."))


;;;; Now try to see what's inside those classes
(let* ((class (find-class 'another-example))
       (slots (closer-mop:class-direct-slots class))
       (slot-i-am-interested (second slots)))
  (inspect slot-i-am-interested) ; Oh, apparently we have a REFERENCES slot
  ;; Why can't SLOT-VALUE access the REFERENCES slot?
  (slot-value slot-i-am-interested 'references))

请注意,尽管我使用的是MITO,但我访问任何数据库或类似的东西(我认为我不会遇到这个问题,如果我没有使用任何自定义插槽,例如MITO 提供的REFERENCES)。这只是简单的 CLOS/MOP 操作。

通常的输出类似于(确切的输出取决于您的 Common Lisp 实现):

user@linuxstudio:~/dev/lisp/slot-question-so$ sbcl --script example.lisp
To load "mito":
  Load 1 ASDF system:
    mito
; Loading "mito"
....
To load "closer-mop":
  Load 1 ASDF system:
    closer-mop
; Loading "closer-mop"


The object is a STANDARD-OBJECT of type MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS.
0. SOURCE: #S(SB-C:DEFINITION-SOURCE-LOCATION
              :NAMESTRING "/home/user/dev/lisp/slot-question-so/example.lisp"
              :INDICES 163840)
1. NAME: EXAMPLE-REFERENCE
2. INITFORM: NIL
3. INITFUNCTION: NIL
4. INITARGS: (:EXAMPLE-REFERENCE)
5. %TYPE: T
6. %DOCUMENTATION: NIL
7. %CLASS: #<MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::ANOTHER-EXAMPLE>
8. READERS: (EXAMPLE-REFERENCE-ACCESSOR)
9. WRITERS: NIL
10. ALLOCATION: :INSTANCE
11. ALLOCATION-CLASS: NIL
12. COL-TYPE: NIL
13. REFERENCES: (EXAMPLE ID)
14. PRIMARY-KEY: NIL
15. GHOST: NIL
16. INFLATE: "unbound"
17. DEFLATE: "unbound"
> q

因此,显然,我们确实有一个 REFERENCES 插槽。然而,在INSPECT 之后,当我们尝试SLOT-VALUE 槽时,我们得到一个SLOT-MISSING 错误(仅显示回溯的第一行):

Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                    {10005E85B3}>:
  When attempting to read the slot's value (slot-value), the slot REFERENCES is
  missing from the object
  #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE>.

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10005E85B3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
          object ~S.~@:>" {1004B1B803}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
          object ~S.~@:>" {1004B1B803}>)
2: (INVOKE-DEBUGGER #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
          object ~S.~@:>" {1004B1B803}>)
3: (ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
          object ~S.~@:>" "read the slot's value (slot-value)" REFERENCES #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE>)
4: ((:METHOD SLOT-MISSING (T T T T)) #<unused argument> #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE> REFERENCES SLOT-VALUE NIL) [fast-method]
5: ((LAMBDA (SB-PCL::OBJECT) :IN SB-PCL::SLOT-MISSING-INFO) #<MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EXAMPLE-REFERENCE>)
6: ((LAMBDA NIL :IN "/home/user/dev/lisp/slot-question-so/example.lisp"))

那么我怎样才能访问“插槽”REFERENCES?这真的是一个插槽吗?如果没有,我该如何访问它?为什么一个简单的SLOT-VALUE 在这种情况下不起作用?

如果我想了解更多相关信息,您能否指出一些有关此主题的文档以提供更多信息?

我使用SBCL 1.4.5.debian 作为我的 lisp 实现,如果这可能很重要的话。

【问题讨论】:

  • 请记住,插槽名称是符号,因此包很重要。当你写(slot-value slot-i-am-interested 'references)时,你正在寻找一个名为CL-USER::REFERENCES的槽,但这个槽实际上似乎被命名为MITO.CLASS.COLUMN::REFERENCES
  • @jkiiski 谢谢!用'MITO.CLASS.COLUMN::REFERENCES 替换'REFERENCES 解决了我的问题。自从我阅读 lisp 中的包以来已经有一段时间了,所以我不记得有关处理符号和包的许多细节。如果您提供您的评论作为答案,我将很高兴接受它。你怎么知道是MITO.CLASS.COLUMN:: 而不是例如MITO.DAO.COLUMN::MITO.DAO.TABLE::?
  • @jkiiski 我抓住了错误和inspect 输出,都没有提到MITO.CLASS.COLUMN。它看起来像一个神奇的价值,但它确实有效。你是怎么发现/猜到的?
  • 请随意打开问题或为食谱做出贡献!

标签: common-lisp clos mop


【解决方案1】:

插槽名称是符号,因此在使用 SLOT-VALUE / WITH-SLOTS 时,包很重要。在这种情况下,引用插槽似乎由包 MITO.CLASS.COLUMN 中的内部符号命名。

inspector 没有显示包名(因为它很少需要),但是你可以看到 slot 定义的类型是 MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS,所以你可以使用 CLOSER-MOP:CLASS-SLOTS 来查找 slot 定义:

CL-USER> (closer-mop:class-slots (find-class 'MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS))
(#<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::SOURCE>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::NAME>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::INITFORM>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::INITFUNCTION>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::INITARGS>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::%TYPE>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::%DOCUMENTATION>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::%CLASS>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::READERS>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::WRITERS>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::ALLOCATION>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION SB-PCL::ALLOCATION-CLASS>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION MITO.CLASS.COLUMN::COL-TYPE>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION MITO.CLASS.COLUMN::REFERENCES>   ;<-- HERE
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION MITO.CLASS.COLUMN::PRIMARY-KEY>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION MITO.CLASS.COLUMN::GHOST>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION MITO.DAO.COLUMN::INFLATE>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION MITO.DAO.COLUMN::DEFLATE>)

或者,您可以尝试(apropos "references") 来查看所有带有此类符号的包:

CL-USER> (apropos "references")
REFERENCES
:HAS-EXTERNAL-REFERENCES-P (bound)
:REFERENCES (bound)
MITO.CLASS.COLUMN::REFERENCES  ;<-- HERE
MITO.CLASS.COLUMN:TABLE-COLUMN-REFERENCES (fbound)
MITO.CLASS.COLUMN:TABLE-COLUMN-REFERENCES-COLUMN (fbound)
...

【讨论】:

    猜你喜欢
    • 2012-10-17
    • 2015-05-21
    • 2016-01-09
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    • 1970-01-01
    相关资源
    最近更新 更多