如何访问 metaobjects/slot-definition 个插槽?为什么 slot-value 可以访问对象的槽,但不能访问元对象的槽?
How to access metaobjects/slot-definition slots? Why slot-value can access slots of objects but not slots of metaobjects?
我在访问插槽定义之外的插槽时遇到问题。我可以检查 class 对象,查看它们的插槽定义,甚至可以获取有关插槽定义的一些标准信息。但是我无法访问有关插槽定义的用户定义信息。
我已经在谷歌上搜索了很长时间,最终阅读了 CLOS & MOP specifications, a bit of the Lisp Cookbook, about some MOP concepts, and related questions on Whosebug that didn't help much. I even readed a piece of SBCL's implementations,但无济于事。
从我能够组合起来的片段中,我可以通过一些函数访问 SLOT DEFINITION
的许多插槽,例如使用 CLOSER-MOP:SLOT-DEFINITION-NAME
访问 SLOT DEFINITION
的 NAME
插槽(这当然有帮助),但我不能为没有这些功能之一的插槽这样做。例如,在 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"))
那么我怎样才能访问 "slot" REFERENCES
?这真的是插槽吗?如果没有,我该如何访问它?为什么简单的 SLOT-VALUE
在这种情况下不起作用?
如果我想对此有更多了解,您能否指出一些关于此主题的文档以提供更多信息?
我正在使用 SBCL 1.4.5.debian
作为我的 lisp 实现,如果这可能很重要的话。
插槽名称是符号,因此在使用 SLOT-VALUE
/ WITH-SLOTS
时包很重要。在这种情况下,引用插槽似乎由包中的内部符号命名 MITO.CLASS.COLUMN
.
检查器没有显示包名(因为很少用到),但是可以看到slot定义是MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS
类型的,所以可以用CLOSER-MOP:CLASS-SLOTS
找插槽定义:
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)
...
我在访问插槽定义之外的插槽时遇到问题。我可以检查 class 对象,查看它们的插槽定义,甚至可以获取有关插槽定义的一些标准信息。但是我无法访问有关插槽定义的用户定义信息。
我已经在谷歌上搜索了很长时间,最终阅读了 CLOS & MOP specifications, a bit of the Lisp Cookbook, about some MOP concepts, and
从我能够组合起来的片段中,我可以通过一些函数访问 SLOT DEFINITION
的许多插槽,例如使用 CLOSER-MOP:SLOT-DEFINITION-NAME
访问 SLOT DEFINITION
的 NAME
插槽(这当然有帮助),但我不能为没有这些功能之一的插槽这样做。例如,在 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"))
那么我怎样才能访问 "slot" REFERENCES
?这真的是插槽吗?如果没有,我该如何访问它?为什么简单的 SLOT-VALUE
在这种情况下不起作用?
如果我想对此有更多了解,您能否指出一些关于此主题的文档以提供更多信息?
我正在使用 SBCL 1.4.5.debian
作为我的 lisp 实现,如果这可能很重要的话。
插槽名称是符号,因此在使用 SLOT-VALUE
/ WITH-SLOTS
时包很重要。在这种情况下,引用插槽似乎由包中的内部符号命名 MITO.CLASS.COLUMN
.
检查器没有显示包名(因为很少用到),但是可以看到slot定义是MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS
类型的,所以可以用CLOSER-MOP:CLASS-SLOTS
找插槽定义:
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)
...