在这里考虑面向对象。
不要将Exporter 视为一个模块,而应将其视为一个类。将ISA 视为“是”,如“我的模块是 Exporter 的子类”。
您所做的是将您的模块声明为 Exporter 类的子类,这意味着您可以使用 Exporter 类的 import 方法,这有点用处。
要真正解释 Exporter 在做什么,您必须了解 Perl 使用命名空间。想象一下,如果您的程序有一个名为$total 的变量1,但您正在使用的模块也是如此。您的 $total 变量会干扰模块的 $total 变量。
为了防止这种情况,Perl 使用命名空间。您的程序在main 的默认命名空间 中运行。您的模块使用package 函数来声明一个新的命名空间。现在,您和您的模块都可以安全地使用名为$total 的变量。在你的程序中,它实际上是$main::total,而在包中,它是$Package::Name::total. If you want to use something from one _namespace_ in another, you can prepend the _namespace_ on it. Think of the$File::Find::nameand$File::Find::dirvariables you have when you useFile ::查找`。
Exporter 的import 方法所做的是将您的子例程(如果您愿意的话,您的变量)从您的命名空间复制到当前的命名空间。想象一下使用File::Copy 模块,而不能复制 将copy 子例程复制到您的主命名空间。你仍然可以使用它,但你必须给它命名空间的名称:
use File::Copy;
...
File::Copy::copy( $from_file, $to_file );
感谢 Exporter(和 import 方法),您放入包 @EXPORT 数组的任何子例程都被复制到当前命名空间。因此,您可以像这样访问 File::Copyscopy` 子例程:
use File::Copy;
...
copy ( $from_file, $to_file );
这也是为什么您必须将所有这些变量声明为our 而不是my。 my 变量是词法范围,不能在它们声明的地方之外访问。包变量(如$File::Find::name)可以。要让Exporter 找到您的@EXPORT 和@EXPORT_OK 数组,这些必须是包 变量。
现在,需要导出函数...
我们知道并喜欢导出子例程的最古老的模块。您使用 File::Copy、File::Path、File::Find,并且可以立即访问它们的子例程。这是因为他们将他们的子例程放入@EXPORT 数组中。这曾一度被认为是可取的,因为它使您可以立即使用这些功能。
File::Temp 等较新的模块要求您声明要导入的子例程:
use File::Temp qw(tempdir);
...
my $temp_dir = tempdir;
如果我没有那个qw(tempdir),我就无法使用tempdir 函数。
这被认为是礼貌的。该模块正在询问您是否允许导入该函数。这是通过将子例程放入@EXPORT_OK 来完成的。这些只会根据要求导出。
这更好,因为您不必导入所有内容,只需导入您需要的内容。而且,您正在记录这些函数的定义位置。
面向对象的模块根本不导出任何东西,也不需要使用 Exporter。很久没有写一个使用 Exporter 的模块了。
--
1 我们在这里讨论的是包 变量。包变量随处可见。