实际上有两个问题(或者您可能只问一个,但完整的答案必须同时回答两个问题)。
什么时候需要使用 Exporter
当您“使用”某人的 perl 模块时,会执行两个不同的操作。首先是加载他们的包;第二个是调用他们包的'import' sub。
仅仅加载他们的包会导致他们包的内容被定义在他们包的命名空间中。您可以直接使用它,而无需第二步,但您必须使用完整的包名称来引用它的所有子组件等。例如,如果他们的包裹包含:
package Foo::Bar;
sub fabronicate {
print "This is a nice sub!\n";
}
那么任何想要使用 if 的人都必须这样做:
use Foo::Bar;
Foo::Bar::fabronicate();
所有在前面输入 Foo::Bar 的东西都会很快变老。对此的解决方案是在包中声明一个“导入”子。该子将负责将公共子(以及变量和模块应提供的任何其他内容)导出到调用者的命名空间(“使用”模块的包)。
Exporter 模块的作用是为您提供一个“导入”子模块。这意味着您不必编写一些看起来很奇怪的代码来为要导出的所有符号创建别名,这一切都为您完成。
请注意,您不必使用 Exporter。您可以编写自己的导入例程,或者有其他模块来处理导出符号。
或者你可以让使用你的模块的人一直明确地提到包名。这在面向对象的模块中很常见,因为只有类方法(例如构造函数)需要显式地以包名称为前缀。拥有对象实例后,包查找是自动的。例如:
my $o = Foo::Bar->new();
$o->fabronicate();
什么时候需要使用@EXPORT
Exporter 模块需要知道包中定义的符号(子、变量等),哪些应该被导出。通常只会导出一小部分。它会参考一些包变量来找出答案:@EXPORT 和 @EXPORT_OK。
@EXPORT 包含您希望导出给使用您的模块的任何人的符号列表,它们没有明确提及要导入的符号列表。最初这听起来不错,直到您意识到如果您的模块正在导出一些名称,而这些名称也被其他模块导出,则会出现问题。
@EXPORT_OK 包含可以导出的符号列表,如果调用模块特别请求它们。调用模块在“use”语句中使用模块名称后的名称列表来指定这些。
use Foo::Bar qw(fabronicate);
# Now I can call fabronicate directly!
请注意,提供符号列表两种方式都可以:@EXPORT 和 @EXPORT_OK 之间的最大区别在于,当有人使用您的模块但未提供任何列表时会发生什么,如下所示:
use Foo::Bar;
在这种情况下,@EXPORT 中定义的所有内容都会被导入,@EXPORT_OK 中定义的任何内容都不会被导入。
还有一些其他变量允许您指定导入多个符号的标签。 Exporter 文档是查找此内容的最佳位置。