Username: Password:

Perl教学第十四篇Perl5的包和模块
来源:linux宝库作者:linux宝库 发布时间:2007-09-30 00:00:00


  一、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用户写了许多有用的模块,CPAN(Comprehensive Perl Archive Network)的Perl文档有其完整的列表。关于CPAN的更多信息见其网址:http: //www.nease.net/tppmsgs/msgs0.htm#27。

喜欢本文,那就收藏到:

    Del.icio.us Google书签 Digg Live Bookmark Technorati Furl Yahoo书签 Facebook 百度搜藏 新浪ViVi 365Key网摘 天极网摘 和讯网摘 博拉网 POCO网摘 添加到饭否 QQ书签 Digbuzz我挖网
相关评论  我也要评论
还没有关于此文章的相关评论!
  • 昵称: (为空则显示guest)
  • 评论分数: ★ ★ ★★★ ★★★★ ★★★★★
  • 评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
  • 导航
    赞助商
    文章类别
    订阅