【发布时间】:2017-01-10 17:50:38
【问题描述】:
我正在学习构建我的 CL 程序,但现在在使用大型包进行编程时无法使用 CLOS。
package.lisp
(defpackage :my-project.a
(:use :cl)
(:export
create-my-object
my-object
; EXPORT SINGLE SLOTS?
my-slot-1
; my-slot-...
; my-slot-n
; OR EXPORT ALL ACCESSOR-FUNCTIONS?
my-slot-1-accessor
; my-slot-n-accessor...
))
(defpackage :my-project.b
(:use :cl :my-project.a)
(:export print-object-slot))
src.lisp
虽然类 MY-OBJECT 是在 MY-PROJECT.A 中定义的
(in-package :my-project.a)
(defclass my-object ()
((my-slot-1 :accessor my-slot-1-accessor :initarg :my-slot-1)
;... more slots
; (my-slot-2 :accessor my-slot-2-accessor :initarg :my-slot-2)
; (my-slot-n :accessor my-slot-n-accessor :initarg :my-slot-n)
))
作为对象的一些 CREATOR 函数
(defun create-my-object ()
(make-instance 'my-object
:my-slot-1 "string"
;; further slots...
))
具有一些功能,例如MY-PROJECT.B 包中的 PRINT-OBJECT, 它应该处理从函数实例化的对象
(in-package :my-project.b)
(defun print-object-slot (slot-name object)
(format nil "slot-value: ~a" (SLOT-VALUE object slot-name)))
问题
执行以下代码时不起作用
(in-package :my-project.b)
(describe 'my-object) ; works
(print-object-slot
'my-slot-1 ; while this works: 'my-project.a:my-slot-1 [if slot is exported]
(create-my-object))
;; ==> slot MY-PROJECT.B:MY-SLOT-1 is missing from the object
;; MY-PROJECT.A:MY-OBJECT
要以编程方式访问我的插槽,在这种情况下,我需要将原始包名与插槽名合并,以从外部类获取/设置插槽...
我的理解
来自 CLOS 对象的访问函数是通用函数,属于包,它们已通过 DEFCLASS 定义,在本例中为:MY-PROJECT.A
由 MY-PROJECT.B 中的 (use-package :my-project.a) 导入导出的符号,这就是 DESCRIBE 起作用的原因。但不包括通用插槽访问器功能的符号。
注意事项: 不应计划程序的体系结构来共享/导出对象和插槽访问。它不适合批量导入/导出插槽/访问器功能。
注意事项: 您可以构建一个自定义函数,通过其包中的 slot-accessor-function 获取/设置插槽,因此只有一个接口函数可以导出?
我的问题:
这种处理外部 CLOS 对象的方式似乎不是可行的方法。 如何以合理的方式导出/导入这些访问器函数,而不需要手动列出每个插槽?
编辑/解决方案
我的术语和插槽与访问器函数的使用是导致此问题的原因(非常感谢@RainerJoswig 清理术语)。
我没有使用导出版本的 MY-SLOT-1-ACCESSOR 函数,它可以按预期工作,但如果我想访问每个插槽中的所有插槽,则需要我“批量导出”它们其他外包装。 @sds 很好地展示了如何做到这一点,并指出了我的方法的一般问题。非常感谢:)
在我看来,我希望只导出对象并获得对所有内部函数的完全访问权限。但这对 CLOS 来说是错误的方式,因为符号和方法不共享与类/对象的直接绑定,我必须适应更好的代码组织。
【问题讨论】:
-
请在您的问题中清除插槽名称和访问器函数之间的区别。
-
看来您只需要下定决心导出(或不导出)符号 my-slot-1。如果您认为应该将其导出,请执行此操作。如果您不想在打印对象中以调试方式使用它,请使用 :: 技巧引用它。如果 print-object 不应该访问未导出的符号,请创建一个访问器并将其导出(但我认为我们对包装变得愚蠢)。
标签: common-lisp packages clos