明らかに、外部から見えるAPIは、シンボルをエクスポートすることによって公開されます。しかし...複数のパッケージ(たとえば、A、B、C)があり、Aのエクスポートされたシンボルがすべて外部APIの一部であるとは限らない場合はどうなりますか?それらの一部はBとCに必要です。(同様に、BはAとCの一部のシンボルをエクスポートし、一部は外部APIのシンボルをエクスポートします。Cは「トップレベル」パッケージであり、エクスポートされたすべてのシンボルはパブリック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
パッケージからエクスポートしたいc
。からエクスポートされたシンボルのみがc
パブリックAPIの一部です。
まず、a
:の定義
(defpackage #:a
(:use #:cl))
エクスポートされたシンボルがないことに注意してください:-)
ヘルパーマクロ(Alexandriaを使用):
(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
's'エクスポート':
(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
。