显然,外部可见的API是通过导出符号发布的。但是......如果我有多个包(例如A,B和C)并且A的导出符号并不都是外部API的一部分 - B和C需要它们中的一部分怎么办? (类似地,B为A和C导出一些符号,为外部API导出一些符号; C是'toplevel'包,它的所有导出符号都是公共API的一部分;我想保持模块化并允许A隐藏其内部来自B和C,所以我避免使用'::')。
我现在的解决方案是重新导出C中要公开的所有内容,并记录公共API仅包含C的导出符号,并且人们应该在错误和痛苦的情况下远离A和B的公共符号当内部接口发生变化时,代码将在未来被破坏。
有更好的方法吗?
更新:这是我对Xach答案理解的实现:
首先,让我完成我的例子。我想从包symbol-a-1
导出符号symbol-a-2
和a
,从包symbol-b-1
导出符号symbol-b-2
和b
以及符号api-symbol-1
来自包api-symbol-2
的{{1}}。只有从c
导出的符号才是公共API的一部分。
首先,c
的定义:
a
请注意,没有任何导出的符号: - )
辅助宏(使用亚历山大):
(defpackage #:a
(:use #:cl))
使用宏来“私下导出”:-):
(defmacro privately-export (package-name &body symbols)
`(eval-when (:compile-toplevel :load-toplevel :execute)
(defun ,(alexandria:format-symbol *package*
"IMPORT-FROM-~a"
(symbol-name package-name)) ()
(list :import-from
,package-name
,@(mapcar (lambda (to-intern)
`',(intern (symbol-name to-intern) package-name))
symbols)))))
现在定义(privately-export :a :symbol-a-1 :symbol-a-2)
:
b
... (defpackage #:b
(:use #:cl)
#.(import-from-a))
的'出口':
b
... (privately-export :b :symbol-b-1 :symbol-b-2)
的定义:
c
这种方法存在问题:
(defpackage #:c
(:use #:cl)
#.(import-from-a)
#.(import-from-b)
(:export :api-symbol-1 :api-symbol-2)
无法使用a
中的符号(在b
import
之后b
中没有a
个符号; package:symbol
基本上不适用于“私下”导出的符号(它只是symbol
或package::symbol
)。答案 0 :(得分:2)
如果A和B主要用于实现C,那么你可以选择性地使用:import-from
来使用C的defpackage表单驱动器,因为你可以导入非外部的东西。然后你可以从那里有选择地重新导出。
答案 1 :(得分:1)
您可以添加第三个包D,它导出所有公共API符号,并将A,B和C包视为私有。然后,您可以使用限定名称(例如
)限定API包中函数和变量的所有定义 (defun D:blah () ...)
可以直观地查看公共入口点的定义。
答案 2 :(得分:1)
可能最简单的方法是由Hans提出。
您可能还想看看Tim Bradshaw的Conduit packages