8.5 多重包 (Multiple Packages)

大的程序通常切分为多个包。如果程序的每个部分都是一个包,那么开发程序另一个部分的某个人,将可以使用符号来作为函数名或变量名,而不必担心名字在别的地方已经被用过了。

在没有提供定义多个命名空间的语言里,工作于大项目的程序员,通常需要想出某些规范(convention),来确保他们不会使用同样的名称。举例来说,程序员写显示相关的代码(display code)可能用 disp_ 开头的名字,而写数学相关的代码(math code)的程序员仅使用由 math_ 开始的代码。所以若是数学相关的代码里,包含一个做快速傅立叶转换的函数时,可能会叫做 math_fft

包不过是提供了一种便捷方式来自动办到此事。如果你将函数定义在单独的包里,可以随意使用你喜欢的名字。只有你明确导出( export )的符号会被别的包看到,而通常前面会有包的名字(或修饰符)。

举例来说,假设一个程序分为两个包, mathdisp 。如果符号 fftmath 包导出,则 disp 包里可以用 math:fft 来参照它。在 math 包里,可以只用 fft 来参照。

下面是你可能会放在文件最上方,包含独立包的代码:

  1. (defpackage "MY-APPLICATION"
  2. (:use "COMMON-LISP" "MY-UTILITIES")
  3. (:nicknames "APP")
  4. (:export "WIN" "LOSE" "DRAW"))
  5. (in-package my-application)

defpackage 定义一个新的包叫做 my-application [1] 它使用了其他两个包, common-lispmy-utilities ,这代表着可以不需要用包修饰符(package qualifiers)来存取这些包所导出的符号。许多包都使用了 common-lisp 包 ── 因为你不会想给 Lisp 自带的操作符与变量再加上修饰符。

my-application 包本身只输出三个符号: WINLOSE 以及 DRAW 。由于调用 defpackage 给了 my-application 一个匿称 app ,则别的包可以这样引用到这些符号,比如 app:win

defpackage 伴随着一个 in-package ,确保当前包是 my-application 。所有其它未修饰的符号会被扣押至 my-application ── 除非之后有别的 in-package 出现。当一个文件被载入时,当前的包总是被重置成载入之前的值。