如果我有一个方法a
和b
的模块,并想要导出它们,我会这样做:
use Exporter;
our @ISA = qw (Exporter);
our @EXPORT = qw (a b);
我不明白这一点是什么:
our @ISA = qw (Exporter);
做什么?
答案 0 :(得分:11)
@Foo::ISA
数组是一个全局变量,用于保存类Foo
继承的类。
通常,您不应直接操纵@ISA
;这样做表明您可能正在查看旧的Perl代码。
如果要声明继承关系,更好的方法是
use parent 'Exporter';
为你调整幕后@ISA
,并做一些其他有用的事情。
在你的情况下,当你做
our @ISA = qw(Exporter)
您将自己的班级声明为Exporter
的子类。 Exporter
类提供了一个名为import
的方法。你为什么这么想?因为当你说
use MyClass;
实际发生的是:
BEGIN {
require 'MyClass.pm';
MyClass->import;
};
每当有人import
上课时,系统会自动调用use
方法。该方法可以做任何你想做的事情。 (如果需要,您可以编写自己的import
),但通常用于将符号导入调用者的命名空间。这就是Exporter
为你做的事情。
但是,Exporter
也会导出自己的import
方法,因此您实际上不必再继承它。 (这是在很久以前修好的。)所以现在你可以说
use Exporter qw(import);
您的软件包将获得import
方法,而不必惹恼@ISA
。
答案 1 :(得分:7)
在这里想想面向对象。
将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 :: name {{1 }} $文件::查找:: DIR and
文件:: Find`。
Exporter的variables you have when you use
方法所做的是将您的子例程(如果您愿意,您的变量)从命名空间复制到当前命名空间。想象一下,使用import
模块,无法将复制到File::Copy
子程序到主命名空间。你仍然可以使用它,但是你必须在它上面给它命名空间名称:
copy
感谢Exporter(以及导入方法),您放入包use File::Copy;
...
File::Copy::copy( $from_file, $to_file );
数组的所有子例程都将复制到当前命名空间。因此,您可以像这样访问File :: Copy @EXPORT
copy`子例程:
s
这也是您必须将所有这些变量声明为use File::Copy;
...
copy ( $from_file, $to_file );
而不是our
的原因。 my
变量是词法范围,并且无法在声明的位置之外访问。包变量(如my
)可以。要让$File::Find::name
找到您的Exporter
和@EXPORT
数组,这些数组必须是包变量。
现在,出口功能的可取性......
我们所知道并且最喜欢的最古老的模块无缘无故地导出子程序。您可以使用File :: Copy,File :: Path,File :: Find,并且可以立即访问其子例程。这是因为他们将子程序放入@EXPORT_OK
数组中。这曾经被认为是可取的,因为它使您可以立即使用这些功能。
@EXPORT
之类的新模块要求您声明要导入的子程序:
File::Temp
如果我没有use File::Temp qw(tempdir);
...
my $temp_dir = tempdir;
,我就无法使用qw(tempdir)
功能。
这被认为是有礼貌的。该模块要求您允许导入该功能。这是通过将子例程放入tempdir
来完成的。这些只会在要求时出口。
这样做更好,因为您不必导入所有内容,只需要您需要的内容。并且,您将记录这些功能的定义位置。
面向对象的模块根本不会导出任何内容,也不需要使用Exporter。自从我编写了一个使用Exporter的模块以来,已经有很长一段时间了。
- 1 我们在这里谈论包变量。包变量随处可见。
答案 2 :(得分:3)
@ISA
包变量用于指定类之间的继承。不鼓励你自己操纵这个变量。如果您想继承其他类,请执行
use parent 'Parent::Class';
或pre v10.1:
use base 'Parent::Class';
在这种特定情况下,继承自Exporter
会使import
方法可用。您的代码可以重写为。
use parent 'Exporter';
our @EXPORT = qw/a b/;
当您的模块为import
d时,会自动调用use
方法,并且可能会将符号导出到使用的包中。
为什么手动使用@ISA
是错误的:
不要分配给@ISA
:其他模块可能已经添加了条目;这会覆盖他们。因此,push @ISA, "Some::Class"
。
避免在运行时修改@ISA
。最好尽可能早地指定继承关系(在解析期间或初始编译之后),这样您的模块就可以在没有限制的情况下使用。您可以将其包装在BEGIN
或CHECK
块中,例如
BEGIN {
push @ISA, "Some::Class";
}
通过parent
继承使这更加容易。如果请求的模块尚未加载,parent
也会编译它:不需要use Some::Class
。
答案 3 :(得分:3)
它指示Perl在Exporter
模块中查找无法在包中找到它们的方法。您希望从Exporter
继承的常用方法是import
方法,即将模块的导出符号复制到调用包的工作。
来自perlobj
:
每个包都包含一个名为
@ISA
的特殊数组。@ISA
数组包含该类的父类的列表(如果有)。当Perl执行方法解析时,将检查此数组,我们将在稍后介绍。
例如,这是一个错误,因为Perl将尝试调用不存在的子例程Foo::some_method
:
sub Bar::some_method { 42 }
my $obj = bless {}, 'Foo';
$obj->some_method;
包中的@ISA
变量告诉Perl在其他包中查找该方法,因此该代码将起作用并调用Bar::some_method
方法。
sub Bar::some_method { 42 }
my $obj = bless {}, 'Foo';
@Foo::ISA = qw(Bar);
$obj->some_method;
这方面的实际应用是继承。
正如amon所提到的,很少需要直接设置@ISA
。 parent
编译指示(以及较旧的,现在不鼓励的base
编译指示)声明继承关系并为您设置此变量。