如果我有一个有方法的模块a,并b与要导出他们我做的:
use Exporter;
our @ISA = qw (Exporter);
our @EXPORT = qw (a b);
Run Code Online (Sandbox Code Playgroud)
我不明白的是这一行:
our @ISA = qw (Exporter);做什么?
fri*_*edo 12
该@Foo::ISA数组是一个全局变量,用于保存类Foo继承的类.
一般来说,你不应该@ISA直接操纵; 这样做表明你可能正在查看旧的Perl代码.
如果要声明继承关系,更好的方法是
use parent 'Exporter';
Run Code Online (Sandbox Code Playgroud)
它会@ISA在幕后为你调整,还会做一些其他有用的东西.
在你的情况下,当你这样做
our @ISA = qw(Exporter)
Run Code Online (Sandbox Code Playgroud)
你宣布你的班级是你的一个子类Exporter.的Exporter类提供一个调用的方法import.你为什么这么想?因为当你说
use MyClass;
Run Code Online (Sandbox Code Playgroud)
实际发生的是:
BEGIN {
require 'MyClass.pm';
MyClass->import;
};
Run Code Online (Sandbox Code Playgroud)
import每当有人use上课时,都会自动调用该方法.该方法可以做任何你想做的事情.(import如果你愿意,你可以自己编写)但通常它用于将符号导入调用者的命名空间.这Exporter对你有什么用.
但是,Exporter也会导出自己的import方法,因此您实际上不必再继承它.(这个问题在很久以前就得到了解决.)所以现在你可以说
use Exporter qw(import);
Run Code Online (Sandbox Code Playgroud)
而你的包将获得import方法而不必乱用@ISA.
在这里思考面向对象.
可以认为Exporter不仅仅是一个模块,而是一个类.可以想象"我的模块是出口商的子类ISA "中的" 是一个 ".
你正在做的是将你的模块声明为Exporter类的子类,这意味着你可以使用importExporter类的方法,这种方法很有用.
要真正解释Exporter正在做什么,您必须了解Perl使用命名空间.想象一下,如果您的程序调用了变量1$total,那么您正在使用的模块也是如此.您的$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 and$ File :: Find :: dir variables you have when you useFile :: Find`.
Exporter的import方法所做的是将子例程(如果您愿意,您的变量)从命名空间复制到当前命名空间.想象一下,使用该File::Copy模块时无法将子例程复制copy到主命名空间.你仍然可以使用它,但你必须在它上面给它命名空间的名称:
use File::Copy;
...
File::Copy::copy( $from_file, $to_file );
Run Code Online (Sandbox Code Playgroud)
由于Exporter(以及导入方法),您放入packages @EXPORT数组的任何子例程都将复制到当前命名空间.因此,您可以s像这样访问File :: Copy copy`子例程:
use File::Copy;
...
copy ( $from_file, $to_file );
Run Code Online (Sandbox Code Playgroud)
这也是为什么你必须声明所有这些变量作为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;
Run Code Online (Sandbox Code Playgroud)
如果我没有qw(tempdir),我就无法使用该tempdir功能.
这被认为是礼貌的.该模块要求您允许导入该功能.这是通过将子程序放入其中来完成的@EXPORT_OK.这些只会根据要求出口.
这样做更好,因为您不必导入所有内容,只需要导入.而且,您正在记录这些功能的定义位置.
面向对象的模块根本不导出任何内容,也不需要使用Exporter.自从我编写了一个使用Exporter的模块以来,已经有很长一段时间了.
- 1我们在这里谈论包变量.包变量随处可见.
包@ISA变量用于指定类之间的继承。不鼓励您自己操纵此变量。如果你想从另一个类继承,那么
use parent 'Parent::Class';
Run Code Online (Sandbox Code Playgroud)
或 v10.1 之前版本:
use base 'Parent::Class';
Run Code Online (Sandbox Code Playgroud)
在这种特定情况下,继承自Exporter使得该import方法可用。您的代码可以重写为。
use parent 'Exporter';
our @EXPORT = qw/a b/;
Run Code Online (Sandbox Code Playgroud)
import当你的模块被调用时,该方法会被自动调用use,并且可能会将符号导出到 using 包中。
为什么手动使用@ISA不好:
不要分配给@ISA:其他模块可能已经向其中添加了条目;这会覆盖它们。所以,push @ISA, "Some::Class"。
避免@ISA在运行时修改。最好尽早指定继承关系(在解析期间或初始编译之后),以便您的模块可以不受限制地在那里使用。您可以将其包装在BEGINorCHECK块中,例如
BEGIN {
push @ISA, "Some::Class";
}
Run Code Online (Sandbox Code Playgroud)通过继承parent使这变得更加容易。parent如果尚未加载,还将编译所请求的模块:不需要use Some::Class.
| 归档时间: |
|
| 查看次数: |
7104 次 |
| 最近记录: |