Perl包和模块
一、require函数
用require函数可以把程序分割成多个文件并创建函数库。例如,在myfile.pl中有定义好的Perl函数,可用语句require("myfile.pl");在程序中Perl包含进来。当Perl解释器看到这一语句,就在内置数组变量@INC指定的目录中寻找文件myfile.pl。如果找到了,该文件中的语句就被执行,否则程序终止并输出错误信息:
Can'tfindmyfile.plin@INC
作为子程序调用参数,文件中最后一个表达式的值成为返回值,require函数查看其是否为零,若为零则终止。例如myfile.pl最后的语句是:
print("hello,world!\n");
$var=0;
因为最后的语句值为零,Perl解释器输出下列错误信息并推出:
myfile.pldidnotreturetruevalue
可以用简单变量或数组元素等向require传递参数,如:
- @reqlist=("file1.pl","file2.pl","file3.pl");
- require($reqlist[$0]);
- require($reqlist[$1]);
- require($reqlist[$2]);
还可以不指定文件名,即:
require;
这时,变量$_的值即作为文件名传递给require。
注:如果@INC中有多个目录中含有同一个文件,则只有第一个被Perl包含。
1、require函数和子程序库
用require函数可以创建可用于所有Perl程序的子程序库,步骤如下:
a、确定存贮子程序库的目录
b、将子程序抽取放到单独的文件中,将文件放到子程序库目录
c、每个文件末尾加一句非零值的语句,最简单的办法是语句1;
d、在主程序中用requirePerl包含一个或多个所需的文件。
e、运行主程序时,用-I选项指定子程序库目录,或者在调用require前将该目录添加到@INC数组中。
例如:假设目录/u/perldir中存有你的Perl子程序库,子程序mysub存贮在文件mysub.pl中。现在来Perl包含上该文件:
unshift(@INC,"/u/perldir");
require("mysub.pl");
对unshift的调用把目录/u/perldir添加到@INC数组,对require的调用将mysub.pl文件的内容Perl包含进来作为程序的一部分。
注意:
1、应该使用unshift来向@INC中添加目录,而不是push。因为push增加到@INC的末尾,则该目录将被最后搜寻。
2、如果你的库文件名与/usr/local/lib/perl中的某文件同名,则不会被Perl包含进来,因为require只Perl包含同名文件中的第一个。
2、用require指定Perl版本
Perl5中,可以用require语句来指定程序运行所需的Perl版本。当Perl解释器看到require后跟着数字时,则只有其版本高于或等于该数字时才运行该程序。例如,下面语句表明只有Perl解释器为5.001版或更高时才运行该程序:
require5.001; #p#
二、Perl包
Perl程序把变量和子程序的名称存贮到符号表中,perl的符号表中名字的集合就称为Perl包(package)。
1、Perl包的定义
在一个程序中可以定义多个Perl包,每个Perl包有一个单独的符号表,定义语法为:
packagemypack;
此语句定义一个名为mypack的Perl包,从此以后定义的所有变量和子程序的名字都存贮在该Perl包关联的符号表中,直到遇到另一个package语句为止。
每个符号表有其自己的一组变量、子程序名,各组名字是不相关的,因此可以在不同的Perl包中使用相同的变量名,而代表的是不同的变量。如:
$var=14;
packagemypack;
$var=6;
第一个语句创建变量$var并存贮在main符号表中,第三个语句创建另一个同名变量$var并存贮在mypackPerl包的符号表中。
2、在Perl包间切换
在程序里可以随时在Perl包间来回切换,如:
- 1:#!/usr/local/bin/perl
- 2:
- 3:packagepack1;
- 4:$var=26;
- 5:packagepack2;
- 6:$var=34;
- 7:packagepack1;
- 8:print("$var\n");
运行结果如下:
$program
26
$
第三行定义了Perl包pack1,第四行创建变量$var,存贮在Perl包pack1的符号表中,第五行定义新Perl包pack2,第六行创建另一个变量$var,存贮在Perl包pack2的符号表中。这样就有两个独立的$var,分别存贮在不同的Perl包中。第七行又指定pack1为当前Perl包,因为Perl包pack1已经定义,这样,所有变量和子程序的定义和调用都为该Perl包的符号表中存贮的名字。因此第八行对$var的调用为pack1Perl包中的$var,其值为26。
3、mainPerl包
存贮变量和子程序的名字的缺省符号表是与名为main的Perl包相关联的。如果在程序里定义了其它的Perl包,当你想切换回去使用缺省的符号表,可以重新指定mainPerl包:
packagemain;
这样,接下来的程序就好象从没定义过Perl包一样,变量和子程序的名字象通常那样存贮。
4、Perl包的引用
在一个Perl包中可以引用其它Perl包中的变量或子程序,方法是在变量名前面加上Perl包名和一个单引号,如:
- packagemypack;
- $var=26;
- packagemain;
- print("$mypack'var\n");
这里,$mypack'var为mypackPerl包中的变量$var。
注意:在Perl5中,Perl包名和变量名用双冒号隔开,即$mypack::var。单引号引用的方式仍然支持,但将来的版本中未必支持。
5、指定无当前Perl包
在Perl5中,可以用如下语句指定无当前Perl包:
package;
这时,所有的变量必须明确指出所属Perl包名,否则就无效--错误。
$mypack::var=21;#ok
$var=21;#error-nocurrentpackage
这种情况直到用package语句指定当前Perl包为止。
6、Perl包和子程序
Perl包的定义影响到程序中的所有语句,Perl包括子程序,如:
- packagemypack;
- subroutinemysub{
- local($myvar);
- #stuffgoeshere
- }
这里,mysub和myvar都是Perl包mypack的一部分。在Perl包mypack外调用子程序mysub,则要指定Perl包:$mypack'mysub。
可以在子程序中切换Perl包:
packagepack1;
subroutinemysub{
$var1=1;
packagepack2;
$var1=2;
}
这段代码创建了两个变量$var1,一个在Perl包pack1中,一个在Perl包pack2中,Perl包中的局域变量只能在其定义的子程序等语句块中使用,像普通的局域变量一样。
7、用Perl包定义私有数据
Perl包最通常的用途是用在含有子程序和子程序所使用的全局变量的文件中,为子程序定义这样的Perl包,可以保证子程序使用的全局变量不可在其它地方使用,这样的数据即为私有数据。更进一步,可以保证Perl包名不可在其它地方使用。私有数据例:
- 1:packageprivpack;
- 2:$valtoprint=46;
- 3:
- 4:packagemain;
- 5:#Thisfunctionisthelinktotheoutsideworld.
- 6:subprintval{
- 7:&privpack'printval();
- 8:}
- 9:
- 10:packageprivpack;
- 11:subprintval{
- 12:print("$valtoprint\n");
- 13:}
- 14:
- 15:packagemain;
- 16:1;#returnvalueforrequire
此子程序只有在调用printval后才能产生输出。
该文件分为两个部分:与外界联系的部分和私有部分。前者为缺省的mainPerl包,后者为Perl包privpack。第6~8行定义的子程序printval可被其它程序或子程序调用。printval输出变量$valtoprint的值,此变量仅在Perl包privpack中定义和使用。第15、16行确保其被其它程序用require语句Perl包含后工作正常,15行将当前Perl包设置回缺省Perl包main,16行返回非零值使require不报错。
8、Perl包和系统变量
下列变量即使从其它Perl包中调用,也在mainPerl包中起作用:
文件变量STDIN,STDOUT,STDERR和ARGV
变量%ENV,%INC,@INC,$ARGV和@ARGV
其它含有特殊字符的系统变量
9、访问符号表
在程序中查找符号表可用数组%_package,此处package为想访问的符号表所属的Perl包名。例如%_main含有缺省的符号表。
通常不需要亲自查找符号表。#p#
三、模块
多数大型程序都分割成多个部件,每一部件通常含有一个或多个子程序及相关的变量,执行特定的一个或多个任务。集合了变量和子程序的部件称为程序模块。
1、创建模块
Perl5中用Perl包来创建模块,方法是创建Perl包并将之存在同名的文件中。例如,名为Mymodult的Perl包存贮在文件Mymodult.pm中(扩展名.pm表示PerlModule)。下例的模块Mymodult含有子程序myfunc1和myfunc2及变量$myvar1和$myvar2。
- 1:#!/usr/local/bin/perl
- 2:
- 3:packageMymodule;
- 4:requireExporter;
- 5:@ISA=qw(Exporter);
- 6:@EXPORT=qw(myfunc1myfunc2);
- 7:@EXPORT_OK=qw($myvar1$myvar2);
- 8:
- 9:submyfunc1{
- 10:$myvar1+=1;
- 11:}
- 12:
- 13:submyfunc2{
- 14:$myvar2+=2;
- 15:}
第3~7行是标准的Perl模块定义方式。第3行定义Perl包,第4行Perl包含内置Perl模块Exporter,6、7行进行子程序和变量的输出以与外界联系。第6行创建名为@EXPORT的特殊数组,该数组中的子程序可以被其它程序调用,这里,myfunc1和myfunc2可以被访问。其它任何在模块中定义但没有赋给数组@EXPORT的子程序都是私有的,只能在模块内部调用。第7行创建另一个名为@EXPORT_OK的特殊数组,其中含有可被外部程序访问的变量,这里含有$myvar1和$myvar2。
2、导入模块
将模块导入你的Perl程序中使用use语句,如下句导入了Mymodule模块:
useMymodule;
这样,模块Mymodule中的子程序和变量就可以使用了。
取消导入模块使用no语句,如下句取消了Mymodule模块的导入:
noMymodule;
下面看一个导入模块和取消导入的例子,使用integer模块要求所有数字运算基于整数,浮点数在运算前均被转化为整数。
- 1:#!/usr/local/bin/perl
- 2:
- 3:useinteger;
- 4:$result=2.4+2.4;
- 5:print("$result\n");
- 6:
- 7:nointeger;
- 8:$result=2.4+2.4;
- 9:print("$result\n");
程序输出如下:
$program
4
4.8
$
如果use或no语句出现在语句块中,则只在该块的有效范围内起作用,如:
- useinteger;
- $result1=2.4+2.4;
- if($result1==4){
- nointeger;
- $result2=3.4+3.4;
- }
$result3=4.4+4.4;
结果输出如下:
4
6.8
8
这里,no语句只在if语句中有效,出了if语句仍使用integer模块,因此4.4在做加法前被转化成了4。
3、预定义模块
Perl5提供了许多有用的预定义模块,可以用use导入和no语句取消。下面是库中最有用的一些模块:
Perl文档中有完整的预定义模块列表。
注:世界各地的Perl5用户写了许多有用的模块,CPAN(ComprehensivePerlArchiveNetwork)的Perl文档有其完整的列表。关于CPAN的更多信息见其网址:http://www.perl.com/perl/CPAN/README.html。
【编辑推荐】
本文和大家重点讨论一下Perl包和模块的概念,多数大型程序都分割成多个部件,每一部件通常含有一个或多个子程序及相关的变量,执行特定的一个或多个任务。集合了变量和子程序的部件称为程序模块。