|
|
第十四章 Perl5的包和模块
by
flamephoenix
一、require函数
1、require函数和子程序库
2、用require指定Perl版本
二、包
1、包的定义
2、在包间切换
3、main包
4、包的引用
5、指定无当前包
6、包和子程序
7、用包定义私有数据
8、包和系统变量
9、访问符号表
三、模块
1、创建模块
2、导入模块
3、预定义模块
一、require函数
用require函数可以把程序分割成多个文件并创建函数库。例如,在myfile.pl中有定义好的Perl函数,可用语句require
("myfile.pl"); 在程序中包含进来。当Perl解释器看到这一语句,就在内置数组变量@INC指定的目录中寻找文件myfile.pl。如果找到了,该文件中的语句就被执行,否则程序终止并输出错误信息:
Can't find myfile.pl in @INC
作为子程序调用参数,文件中最后一个表达式的值成为返回值,require函数查看其是否为零,若为零则终止。例如myfile.pl最后的语句是:
print ("hello, world!\n");
$var = 0;
因为最后的语句值为零,Perl解释器输出下列错误信息并推出:
myfile.pl did not reture true value
可以用简单变量或数组元素等向require传递参数,如:
@reqlist = ("file1.pl", "file2.pl", "file3.pl");
require ($reqlist[$0]);
require ($reqlist[$1]);
require ($reqlist[$2]);
还可以不指定文件名,即:
require;
这时,变量$_的值即作为文件名传递给require。
注:如果@INC中有多个目录中含有同一个文件,则只有第一个被包含。
1、require函数和子程序库
用require函数可以创建可用于所有Perl程序的子程序库,步骤如下:
a、确定存贮子程序库的目录
b、将子程序抽取放到单独的文件中,将文件放到子程序库目录
c、每个文件末尾加一句非零值的语句,最简单的办法是语句 1;
d、在主程序中用require包含一个或多个所需的文件。
e、运行主程序时,用 -I 选项指定子程序库目录,或者在调用require前将该目录添加到@INC数组中。
例如:假设目录/u/perldir中存有你的Perl子程序库,子程序mysub存贮在文件mysub.pl中。现在来包含上该文件:
unshift (@INC, "/u/perldir");
require ("mysub.pl");
对unshift的调用把目录/u/perldir添加到@INC数组,对require的调用将mysub.pl文件的内容包含进来作为程序的一部分。
注意:
1、应该使用unshift来向@INC中添加目录,而不是push。因为push增加到@INC的末尾,则该目录将被最后搜寻。
2、如果你的库文件名与/usr/local/lib/perl中的某文件同名,则不会被包含进来,因为require只包含同名文件中的第一个。
2、用require指定Perl版本
Perl 5中,可以用require语句来指定程序运行所需的Perl版本。当Perl解释器看到require后跟着数字时,则只有其版本高于或等于该数字时才运行该程序。例如,下面语句表明只有Perl解释器为5.001版或更高时才运行该程序:
require 5.001;
二、包
Perl程序把变量和子程序的名称存贮到符号表中,perl的符号表中名字的集合就称为包(package)。
1、包的定义
在一个程序中可以定义多个包,每个包有一个单独的符号表,定义语法为:
package mypack;
此语句定义一个名为mypack的包,从此以后定义的所有变量和子程序的名字都存贮在该包关联的符号表中,直到遇到另一个package语句为止。
每个符号表有其自己的一组变量、子程序名,各组名字是不相关的,因此可以在不同的包中使用相同的变量名,而代表的是不同的变量。如:
$var = 14;
package mypack;
$var = 6;
第一个语句创建变量$var并存贮在main符号表中,第三个语句创建另一个同名变量$var并存贮在mypack包的符号表中。
2、在包间切换
在程序里可以随时在包间来回切换,如:
1: #!/usr/local/bin/perl
2:
3: package pack1;
4: $var = 26;
5: package pack2;
6: $var = 34;
7: package pack1;
8: print ("$var\n");
运行结果如下:
$ program
26
$
第三行定义了包pack1,第四行创建变量$var,存贮在包pack1的符号表中,第五行定义新包pack2,第六行创建另一个变量$var,存贮在包pack2的符号表中。这样就有两个独立的$var,分别存贮在不同的包中。第七行又指定pack1为当前包,因为包pack1已经定义,这样,所有变量和子程序的定义和调用都为该包的符号表中存贮的名字。因此第八行对$var的调用为pack1包中的$var,其值为26。
3、main包
存贮变量和子程序的名字的缺省符号表是与名为main的包相关联的。如果在程序里定义了其它的包,当你想切换回去使用缺省的符号表,可以重新指定main包:
package main;
这样,接下来的程序就好象从没定义过包一样,变量和子程序的名字象通常那样存贮。
4、包的引用
在一个包中可以引用其它包中的变量或子程序,方法是在变量名前面加上包名和一个单引号,如:
package mypack;
$var = 26;
package main;
print ("$mypack'var\n");
这里,$mypack'var为mypack包中的变量$var。
注意:在Perl 5中,包名和变量名用双冒号隔开,即$mypack::var。单引号引用的方式仍然支持,但将来的版本中未必支持。
5、指定无当前包
在Perl 5中,可以用如下语句指定无当前包:
package;
这时,所有的变量必须明确指出所属包名,否则就无效--错误。
$mypack::var = 21; #ok
$var = 21; #error - no current package
这种情况直到用package语句指定当前包为止。
6、包和子程序
包的定义影响到程序中的所有语句,包括子程序,如:
package mypack;
subroutine mysub {
local ($myvar);
# stuff goes here
}
这里,mysub和myvar都是包mypack的一部分。在包mypack外调用子程序mysub,则要指定包:$mypack'mysub。
可以在子程序中切换包:
package pack1;
subroutine mysub {
$var1 = 1;
package pack2;
$var1 = 2;
}
这段代码创建了两个变量$var1,一个在包pack1中,一个在包pack2中,包中的局域变量只能在其定义的子程序等语句块中使用,像普通的局域变量一样。
7、用包定义私有数据
包最通常的用途是用在含有子程序和子程序所使用的全局变量的文件中,为子程序定义这样的包,可以保证子程序使用的全局变量不可在其它地方使用,这样的数据即为私有数据。更进一步,可以保证包名不可在其它地方使用。私有数据例:
1 : package privpack;
2 : $valtoprint = 46;
3 :
4 : package main;
5 : # This function is the link to the outside world.
6 : sub printval {
7 : &privpack'printval();
8 : }
9 :
10: package privpack;
11: sub printval {
12: print ("$valtoprint\n");
13: }
14:
15: package main;
16: 1; # return value for require
此子程序只有在调用printval后才能产生输出。
该文件分为两个部分:与外界联系的部分和私有部分。前者为缺省的main包,后者为包privpack。第6~8行定义的子程序printval可被其它程序或子程序调用。printval输出变量$valtoprint的值,此变量仅在包privpack中定义和使用。第15、16行确保其被其它程序用require语句包含后工作正常,15行将当前包设置回缺省包main,16行返回非零值使require不报错。
8、包和系统变量
下列变量即使从其它包中调用,也在main包中起作用:
文件变量STDIN, STDOUT, STDERR 和 ARGV
变量%ENV, %INC, @INC, $ARGV 和 @ARGV
其它含有特殊字符的系统变量
9、访问符号表
在程序中查找符号表可用数组%_package,此处package为想访问的符号表所属的包名。例如%_main含有缺省的符号表。
通常不需要亲自查找符号表。
三、模块
多数大型程序都分割成多个部件,每一部件通常含有一个或多个子程序及相关的变量,执行特定的一个或多个任务。集合了变量和子程序的部件称为程序模块。
1、创建模块
Perl 5中用包来创建模块,方法是创建包并将之存在同名的文件中。例如,名为Mymodult的包存贮在文件Mymodult.pm中(扩展名.pm表示Perl
Module)。下例的模块Mymodult含有子程序myfunc1和myfunc2及变量$myvar1和$myvar2。
1 : #!/usr/local/bin/perl
2 :
3 : package Mymodule;
4 : require Exporter;
5 : @ISA = qw(Exporter);
6 : @EXPORT = qw(myfunc1 myfunc2);
7 : @EXPORT_OK = qw($myvar1 $myvar2);
8 :
9 : sub myfunc1 {
10: $myvar1 += 1;
11: }
12:
13: sub myfunc2 {
14: $myvar2 += 2;
15: }
第3~7行是标准的Perl模块定义方式。第3行定义包,第4行包含内置Perl模块Exporter,6、7行进行子程序和变量的输出以与外界联系。第6行创建名为@EXPORT的特殊数组,该数组中的子程序可以被其它程序调用,这里,myfunc1和myfunc2可以被访问。其它任何在模块中定义但没有赋给数组@EXPORT的子程序都是私有的,只能在模块内部调用。第7行创建另一个名为@EXPORT_OK的特殊数组,其中含有可被外部程序访问的变量,这里含有$myvar1和$myvar2。
2、导入模块
将模块导入你的Perl程序中使用use语句,如下句导入了Mymodule模块:
use Mymodule;
这样,模块Mymodule中的子程序和变量就可以使用了。
取消导入模块使用no语句,如下句取消了Mymodule模块的导入:
no Mymodule;
下面看一个导入模块和取消导入的例子,使用integer模块要求所有数字运算基于整数,浮点数在运算前均被转化为整数。
1: #!/usr/local/bin/perl
2:
3: use integer;
4: $result = 2.4 + 2.4;
5: print ("$result\n");
6:
7: no integer;
8: $result = 2.4 + 2.4;
9: print ("$result\n");
程序输出如下:
$ program
4
4.8
$
如果use或no语句出现在语句块中,则只在该块的有效范围内起作用,如:
use integer;
$result1 = 2.4 + 2.4;
if ($result1 == 4) {
no integer;
$result2 = 3.4 + 3.4;
}
$result3 = 4.4 + 4.4;
结果输出如下:
4
6.8
8
这里,no语句只在if语句中有效,出了if语句仍使用integer模块,因此4.4在做加法前被转化成了4。
3、预定义模块
Perl 5提供了许多有用的预定义模块,可以用use导入和no语句取消。下面是库中最有用的一些模块:
integer |
使用整数运算 |
Diagnostics |
输出较多的诊断信息(警告) |
English |
允许英文名用作系统变量的别名 |
Env |
导入环境变量的Perl模块 |
POSIX |
POSIX标准(IEEE 1003.1)的Perl接口 |
Socket |
装载C语言的套接字处理机制 |
Perl文档中有完整的预定义模块列表。
标准模块
下面是所有Perl现行版本(5.004)所附的模块和Pragma:
表B-1 一般程序设计:杂项
模块 功能
autouse 延后载入模块,直到被用到为止
constant 产生编译时常数
Benchmark 检查并比较程序代码的执行时间
Config 存取Perl的配置信息
Env 载人环境变量
English 使用英语或awk的名称代替标点符号
FindBin 寻找目前执行中程序的所在路径
Getopt::Long 命令行参数的延伸处理项目
Getopt::Std 处理单一字符开关
1ib 在编译时处理@INCShell在Perl中透明地执行
Shell 命令
strict 拒绝不安全的结构
Symbol 产生无名glob;检查变量名称
subs 预先声明(predeclare)函数名称
vars 预先声明全局变量名称
表B-2 一般程序设计:错误处理与记录
模块 功能
Carp 产生出错信息
diagnostics 强迫产生详细的警告信息
sigtrap用stack 追踪未预期发生的signal
Sys::Syslog Perl和 UNIX syslob(3)的界面
表B-3 一般程序设计:文件存取与处理
模块 功能
Cwd 取得现行工作目录的路径名
DirHandle 提供处理目录代码的对象方法
Fcntl 载入C的Fcntl.h中的定义
File::Basename 分割文件名数据
File::CheckTree 对一连串文件串做许多测试
File::Copy 拷贝文件或文件句柄
File::Find 寻找文件
File::Path 产生或移除一连串目录
FileCache 允许打开多于系统限制的文件句柄
FileHandle 提供处理文件句柄的对象方法
SelectSaver 储存并还原选择的文件句柄
表B-4 一般程序设计:I/O类别
模块 功能
IO IO::*类的最上层界面
IO::File 处理文件句柄的对象方法
IO::Handle 处理I/O代码的对象方法
IO::Pipe 处理管道的对象方法
IO::SeekableI/O 对象和寻找有关的方法
IO::Select 选择用的对象界面
IO::Socket socket的对象界面
表B-5 一般程序设计:文字处理与屏幕界面
模块 功能
locale 内置运算使用 POSIX locale
Pod::HTML 把pod数据转成HTML
Pod::Text 把pod数据转成ASCII文本
Search::Dict 在字典文件中寻找某字
Term::Cap Termcap界面
Term::Complete 文字完成(word completion)模块
TextxAbbrev 由列表建造缩写表
Text::ParseWords 切割字符串
Text::Soundex 实作 Knuth的 Soundex演算法
Text::Tabs 扩张(expand)及不扩张tab
Text::Wrap 把文字包成段落
表B-6 数据库界面
模块 功能
AnyDBM_File 提供各种 DBM的框架(framework)
DB_File 存取 Berkeley DB
DBGDBM_File 存取 GDBM函数库
NDBM_File 存取 NDBM文件
ODBM_File 存取 ODBM文件
SDBM_File 存取 SDBM文件
表B-7 数字模块
模块 功能
Integer 用整数运算取代双精确数
Math::BigFloat 任意长度浮点数package
Math::BigInt 任意长度整数package
Math::Complex 复数 package
表 B-8 WWW
模块 功能
CGI 通用网关界面(Common Gateway Interface)
CGI::Apache Apache的 Perl模块
CGI:Carp 记录服务器发生的错误
CGI::Fast 支持 FastCGI(Persistent Sever Process)
CGI::Push 支持 server push
CGI::Switch 多种服务器类型的界面
表 B-9 网络与进程间通讯(InterProcess Communication)
模块 功能
IPC::Open2 打开同时读写的进程
IPC::Open3 打开供读、写、记录错误的进程
Net::Ping 检查主机是否与网络连接
Socket 载入C的socket.h中的定义与结构代码
Sys::Hostname 用所有方法尽可能取得主机名称
表 B-10 自动存取CPAN
模块 功能
CPAN CPAN的简单界面
CPAN::FirstTime 产生 CPAN配置文件的公用程序
CPAN::Nox 不用 Compile extension时,执行 CPAN
表B-11 时间与locale
模块 功能
Time::Local 由当地和GMT时间快速计算时间
I18N::Collate 依现行locale比较8-bit的标量数据
表B-12 内建函数的对象界面
模块 功能
Class::Struct 声明类似struct的数据结构当成Perl类
File::Statstat 函数的对象界面
Net::hostent gethost*函数的对象界面
Net::netent getnet*函数的对象界面
Net::protoent getproto*函数的对象界面
Net::servent getserv*函数的对象界面
Time::gmtime gmtime函数的对象界面
Time::localtime localtime函数的对象界面
Time::tm Time::{gm,local}的内部对象
User::grent getgr*函数的对象界面
User::pwent getpw*函数的对象界面
表B-13 高级开发:自动载入与动态载入(autoloading and dynamic loading)
模块 功能
AutoLoader 需要时才载入函
AutoSplit 为自动载入分割package
Devel::SelfStubber 为Selfloading模块产生stub
DynaLoader 动态载人Perl模块
Selfloader 需要时才载入函数
表B-14 为高级开发者设计:语自扩充/跨平台支持
模块 功能
blib 建造模块时寻找blib目录结构
ExtUtils::Enbed 在 C程序中内嵌 Perl的工具程序
ExtUtils::Install 安装文件
ExtUtils::Liblist 决定使用哪些函数库及如何使用
ExtUtils::MakeMaker 产生 Perl扩充用的 Makefile
ExtUtils::Manifest 编写并检查 MANIFEST文件的工具程序
ExtUtils:Miniperl 写 perlmain.c的C程序
ExtUtils::MkbootStrap 产生 DynaLoader用的 bootstrap文件
ExtUtlls::Mksymlists 编写动态扩充(dynamic extension)用的linker选项文件
ExtUtils::MM—OS2 override ExtUtils::MakeMaker中 UNIX特性的方法
ExtUtils::MM—Unix ExtUtils::MakeMaker用的方法
ExtUtlls::MM—VMS Verride ExtUtils::MakeMaker中 UNIX特性的方法
ExtUtils::testlib 修正@INC,只使用内建的扩充机制
Opcode 编译Perl程序代码时,关闭某些opcodeops和 Opcode模块一并使用的Pragma
POS IXIEEE Std l003.1的界面
Safe 执行Perl程序代码时,产生安全的命名空间
Test::Harness 执行Perl标准测试script,并加以统计vmsish开启
VMS 特殊功能
表B-15为高级开发者设计:面向对象的程序设计
模块 功能
Exporter 模块的默认输入(import)方法
overload 重载(overload)Perl的数学运算
Tie::RefHash tie哈希(以参考值为 key)的基类(base class)
Tie::Hash tie哈希的基类
Tie::Scalar tie标量的基类
Tie::SubstrHash 字段大小固定,key长度固定的哈希
UNIVERSAL 所有类的基类
注:世界各地的Perl 5用户写了许多有用的模块,CPAN(Comprehensive
Perl Archive Network)的Perl文档有其完整的列表。关于CPAN的更多信息见其网址:http://www.perl.com/perl/CPAN/README.html。
CPAN:标准函数库之外的选择
如果标准函数库无法满足你的需要,通常还是有别人写好的程序可以用。基于许多复杂的因素,许多模块并未跟随Perl一起散布出去,不过都可以在CPAN找到。
下面是CPAN上所有模块的主要分类:
* 打印格式模块
* Perl核心模块,Perl语言扩充与注记工具
* 开发支持工具
* 操作系统界面
* 网络、装置控制(modem)、进程间通信(interprocess communication)
* 数据结构、数据结构工具
* 数据库界面
* 用户界面
* 其他程序语言的界面或模拟机制
* 文件名、文件系统、文件锁定
* 字符串处理,语言句式处理、语意分析、寻找
* 选项、参数、及配置文件处理
* 多语系支持
* 认证、安全、加密
* WWW、 HTML、 HTTP、 CGI、 MIME
* 服务器与daemon工具
* archiving、压缩、转换工具
* 图像、点阵图处理、绘图
* 邮件与Usenet新闻
* 流程控制工具(callback与exception)
* 文件句柄、目录句柄、输入/输出流(I/O stream)工具
* Microsoft Windows模块
* 杂项模块
上一章 下一章
目录
|
|