查看perl模块安装目录:find `perl -e ‘print “@INC”‘` -name ‘*.pm’ -print

为什么要写或要模块呢?简言之:代码重用,更多见于写一组工具集,有很多地方是可以避免重写的。如何能把这些独立抽象出来,在需要的时候载入进程序执行,提高编写的效率和减少维护。基于此,我们需要Perl模块,而如何使用这些模块,请参考“理解use_require_do使用方法

需要知道的一些基础知识:
package, main, require, use, Exporter, EXPORT, EXPORT_OK, EXPORT_TAG,了解@INC, %INC, require, use, do 这些概念,用法和区别。

package
包的概念在Perl还是比较简单的。我们可以理解为文件夹。然后再文件夹里面是一堆我们的东东,这个那个的。要找什么,去包里找吧。这是通俗易懂的理解。
学术一点就是,Perl将变量,子程序都存贮到一个符号表中,Perl符号表中名字的集合就是package。

通过几行代码后,就更能理解了。来看看下面的代码:
Greeting.pl
#!/bin/env perl
use strict;
use warnings;
use Carp qw(carp);
sub sayHello{ carp"Hello\n";}
sub sayHi{ carp "Hi\n";}

程序非常简单,两个方法,一个说Hello,一个说Hi,其他的什么都没有。我在这里用Carp模块的carp函数替代print以便打印出更多程序的跟踪信息,这样可以让我们更好的理解,当您运行后什么都不会看到。让我们再写一个程序来调用它看看。
Greeting_test.pl

#!/bin/env perl
use strict;
use warnings;
require "Greeting.pl";
sayHello();

运行Greeting_test.pl之后,你可能希望输出Hello。但是屏幕输出

$ ./Greeting_test.pl
Greeting.pl did not return a true value at ./Greeting_test.pl line 5.

信息提示一目了然,Greeting.pl没有返回True。require没有能够成功加载Greeting.pl, 程序报错退出。
虽然是退出了,但是不代表require没能成功编译文件,如果大家对require加载的步骤了解的话,就知道原因了。我们修改一下Greeting_test.pl

#!/bin/env perl
use strict;
use warnings;
eval{ require "Greeting.pl" };
 
sayHello();

用eval捕获require遇到的错误,这样程序还是可以继续运行,结果是
Hello
 at Greeting.pl line 5
  main::sayHello() called at Greeting_req.pl line 5

Hello还是被成功打印出来了,后面的语句只是用来跟踪程序的。用eval来绕过require带来的异常错误的,报错没有被打印出来,它保存在$@中。只是为了可以更好理解require所作的工作,通常情况下,我们会让被调用的文件或模块强制返回一个True。传统上的做法是在程序的最后一行加入”1;”。现在Greeting.pl变成了:

#!/bin/env perl
use strict;
use warnings;
use Carp qw(carp);
sub sayHello{ carp"Hello\n";}
sub sayHi{ carp "Hi\n";}
1;

现在我们可以去掉Greeting_test.pl中的eval了,程序会返回同样的结果。
Hello
 at Greeting.pl line 5
  main::sayHello() called at Greeting_req.pl line 5

让我们来看看第三行的内容,main::sayHello()
,这里的意思是main::sayHello()

Greeting_test.pl 中的第5行被调用了,那么main::是什么呢,这个就是package。所有未明确指定package的变量,子程序都会被存放到main这个包里去。 现在是讨论模块的时候,我不喜欢pl结为,我把他改成更像是Perl模块的文件,以pm结尾,然后再在Greeting_test.pl中作相应的修改,顺便把require换成use,这样做,便于之后可以少写几行代码。 最后我们在Greeting.pm指定模块名为Greeting。最后的代码是:
Greeting.pm
#!/bin/env perl
package Greeting;
use strict;
use warnings;
use Carp qw(carp);

sub sayHello{ carp "Hello\n"; }
sub sayHi{ carp "Hi\n"; }
1;

Greeting_test.pl

#!/usr/bin/perl
use strict;
use warnings;
use Greeting;
 
sayHello();

现在让我们运行一下Greeting_test.pl.
结果返回
$ ./Greeting_test.pl
Undefined subroutine &main::sayHello called at ./Greeting_test.pl line 6.

错误报告显示未定义的子程序&main::sayHello。这正是由于我们在Greeting.pm中改变了包名,所以程序将Greeting.pm中的所有变量以及子程序名都存储在了位于Greeting包的符号表中。这样我们访问sayHello子程序的方法就要通过包名::子程序名,这样的方式访问了。如果不指定包名,perl会main包的符号表中找sayHello,当然我们知道sayHello已经不在那里了。现在我们通过包名::子程序名,这样的方式访问:
Greeting::sayHello();

嗯,我们又看到了Hello出现在屏幕上。这样的访问方式实在是太繁琐,为什么一定要使用包呢?包能很好的解决了变量,子程序名重名的问题。试想一下,如果没有指定包名那么,如果在你的Perl程序与模块里的变量与子程序名同名会怎样。
Greeting_test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Greeting;
use Carp qw(carp);
 
sayHello();
sub sayHello{
  carp "Hello from Greeting_test\n";
}

让我们在Greeting.pm中注释package Greeting;这一行,然后运行
$ ./Greeting_test.pl
Hello from Greeting_test
at ./Greeting_test.pl line 6
main::sayHello() called at ./Greeting_test.pl line 7

模块的sayHello被屏蔽了。这样的结果或许是你想要的,或者是你不想看到的,重要的是,我们失去了模块的sayHello子程序包的概念应该已经很清楚了。

-----
Exporter
现在我们也许希望可以在模块中指定包名,又希望通过直接调用子程序名的方式来执行。嗯,这样的需求很合理。让我们在Greeting.pm中加点什么。如果大家已经了解require和use的区别的话,就一定知道使用require时我们可以直接调用import这个子程序来导出我们呢所需要的子程序名或者变量。
require Greeting;
Greeting->import(qw(sayHello sayHi));

Perl中的符号表是可以操作的,符号表是一个类似于哈希的结构,但他不是一个完整的哈希,他不具备所有哈希的特性以及所有可能的对于哈希进行操作的函数,不过我们可将其看作为一个哈希。可以思考一下,其实我们在import子程序中,将所有不同包中的变量以及子程序名的应用加入到main包的符号表哈希中,不就可以直接使用了嘛,的却就是这样简单。
Greeting.pm

#!/bin/env perl
package Greeting;
use strict;
use warnings;
use Carp qw(carp);
 
sub import{
 no strict 'refs';
 foreach (@_) {
  *{"main::$_"}=\&$_;
 }
}
sub sayHello{ carp "Hello\n"; }
sub sayHi{ carp "Hi\n"; }

Greeting_test.pl
#!/usr/bin/perl
use strict;
use warnings;
use Greeting qw(sayHello);
use Carp qw(carp);
 
sayHello();

use Greeting qw(sayHello)
相当于调用了Greeting.pm的import方法并将sayHello作为参数传入了Greeting模块的import的子程序。在import的子程序中所作的操作就是之前所说将Greeting包中的变量以及子程序名的应用加入到main包的符号表哈希中。现在sayHello又可以像先前一样正常工作了,但如果我们不在main包中,而是在其他包中调用呢,这样的方法就显得有太多的限制了。庆幸的是,现在有一个标准的import子程序在Exporter模块中,我们要做的仅仅是加入一行:
use Exporter;

这样,import子程序就能够导出方法给调用者所在的包了。

@EXPORT
Exporter模块中的import会检查列表@EXPORT来确定哪些变量已经子程序在默认状态下被导出,例如在Greeting模块里:
package Greeting;
our @EXPORT=qw(sayHello);
use Exporter;

这就表示在默认情况下sayHello也会被导出如果我们不指定import的列表时。

use Greeting;
BEGIN { require Greeting; Greeting->import }

以上两行的代码,效果是一样的。虽然import
list没有被提供,但是sayHello也会被导入进来。这里的import后面没有导入列表,这个导入一个空列表是不一样的,导入一个空列表代表模块的import子程序不会被调用。

@EXPORT_OK
假如我们希望一些子程序或者变量不被默认的导入,同时他们可以在需要时被导入。这样我们可以把把这些子程序或者变量加入到名为@EXPORT_OK的列表中。
package Greeting;
our @EXPORT=qw(sayHello);
our @EXPORT_OK=qw(sayHi);
use Exporter;

use Greeting qw(sayHello sayHi);
这样sayHello和sayHi现在都被导入了。但是如果我们这样写:
use Greeting qw(sayHi);

虽然sayHello出现在@EXPORT列表中代表默认导入,但是如果在我们指定了import
list的话,默认的@EXPORT会被忽略。所以,在这种情况下,我们不再能够直接对sayHello进行调用。总而言之,任何被在import list被指定导入的变量或者子程序必须出现在@EXPORT或者@EXPORT_OK中。

现在我们似乎可以对所导入的内容进行了限制,但是这样的方法不会阻止类似于包名::变量名(子程序名)这样的调用。但如果出现这样的情况,我们至少就能知道那些不希望被调用子程序或者变量正在被调用。

%EXPORT_TAGS
实际上,我们没有必要一一指定那些需要被导入的变量已经子程序,这里是有快捷方式的。那些我们需要被导入的变量和子程序可以被组合起来,然后打上标签。这样只要标签被导入,标签下的变量以及子程序就同样被导入了。导入标签的形式是:
use Greeting qw(:DEFAULT);

用一个冒号后面紧紧跟着的就是标签名。这样子就导入了位于DEFAULT标签下的所有变量和子程序。嗯,这个似乎没有什么用处吗,要导入默认的话,直接全部添加进@EXPORT列表里就好了,何必再创建一个标签呢?当然我们还可以这样用:
use Greeting qw(:DEFAULT sayHi);

这样有用多了,DEFAULT标签下的所有东东和sayHi子程序一起被导入了。

类似这样的导入方法在实际应用当中很少能够看见。原因是,提供一个导入列表的目的是能够在程序中实现对模块子程序使用的控制。但是对同一个模块,我们可能会修改一些原来的实现方法,又或者是添加了一些新的功能和变量。那么对于一个有着很多子程序或变量的模块来说,这些修改或者添加都可能导致与调用该模块的程序产生冲突而不能正常工作。标签的方法并不能将我们的程序从这种潜在的危险中隔离开来。在Perl中,我们有着其他的一些方法来提供更细节的控制。这里我们以后再讨论。

现在让我们看看如何在模块中定义TAGS
#!/bin/env perl
package Greeting;
use strict;
use warnings;
use Carp qw(carp);
use Exporter;
 
our @EXPORT=qw(sayHello);
our @EXPORT_OK=qw(sayHi);
our %EXPORT_TAGS=(
    all => [@EXPORT,@EXPORT_OK],
    sayHi => [qw(sayHi)],
);
sub sayHello{ carp "Hello\n"; }
sub sayHi{ carp "Hi\n"; }
1;

EXPORT_TAGS是一个哈希,我们只需要将包含变量或者子程序名的匿名数组赋值给以标签名为键的哈希并可以创建我们上面所提到的快捷方式了。

总结

模块调用风格:传统的和面向对象的.
传统风格的模块:为调用者导入和使用定义的子例程和变量
面象对象风格的模块:以类来调用

所以模块有二种方法来为它的接口提供给程序来使用:导出符号,要不就是允许方法调用。
 
模块加载
编译时时行一次预装载,然后给需要的符号输入进来,这样编译后,在运行时就可以使用这些模块中的符号(子例程和变量)。

注意:如果没有提供所需要的符号LIST(列表),那么就使用模块中内部的@EXPORT数组中命名的符号;如果提供了这个列表,还需要在模块本身有的
@EXPORT要不是在@EXPORT_OK数组中提取。
 
模块名字
建议名字第一个字母大写,除非其是pragma的作用。

require和use的分别
请参考:理解use_require_do使用方法

基本模块样例
package Freeoa;
require Exporter;
 
our @ISA = qw(Exporter);
our @EXPORT = qw(camel); #默认导出的符号
our @EXPORT_OK = qw($weight); #按要求导出的符号
our %EXPORT_TAGS = (camel => [qw(camel $weight)]); #导出时的符号组
our $VERSION = 1.00;
 
sub camel {print  "TEST"};
$weight = 1024;
1;

@EXPORT数组包含默认导出的变量和函数的名字,当use
packagename时就会得到的东西,@EXPORT_OK中的变量和函数只有当程序中use语句中特别要求时才会导出。最 后%EXPORT_TAGS中的键值对允许程序包含那些在@EXPORT和@EXPORT_OK中列出的特定的符号组,如果不想外面的模块导出什么,可以 使用@EXPORT_FAIL来实现。

符号组因为一定需要出现在@EXPORT和@EXPORT_OK中,因此perl提供了二个函数来处理
%EXPORTER_TAGS = (foo => [qw(aa bb cc)],bar => [qw(aa cc dd)]);

Exporter::export_tags('foo'); #给aa,bb和cc导入到@EXPORT

Exporter::export_ok_tags('bar'); #给aa,cc和dd导入到@EXPORT_OK

来源:网络

perl模块的更多相关文章

  1. Linux CPAN Perl 模块安装

    当我们想使用某些Perl模块的时候,很可能会遇到当前系统不存在这个模块的情况,这时我们可以通过使用CPAN来对相应的模块进行获取,下面就介绍一下CPAN的使用方法.首先,我们可以用perl -e 'u ...

  2. Linux下安装与使用本地的perl模块

    转自 http://www.cnblogs.com/xianghang123/archive/2012/08/23/2652806.html Linux下安装与使用本地的perl模块 在使用Linux ...

  3. perl 简单学习,安装perl模块

    检查是否安装了某个perl模块 有多种方式 0.perldoc perlinstall 列出所有的模块及版本号 1. perl -M模块名 -e 1(模块名不加空格) 没有返回值则说明有此模块 2.p ...

  4. linux 查看是否安装perl模块

    这里介绍两种linux中查看perl模块是否安装的方法,一种是对于单体的模块,一种是对于群体的. 单体验证: [root@root ~]# perl -MShell -e "print\&q ...

  5. linux安装perl模块

    查询perl CPAN模块   shell>perl -MCPAN -e shell cpan>install module_name   手动安装perl CPAN模块 从 CPAN(h ...

  6. perl模块安装

    转自: http://www.cnblogs.com/itech/archive/2009/08/10/1542832.html http://www.mike.org.cn/blog/index.p ...

  7. 搭建MHA时 yum 安装perl模块提示 baseurl 错误

    今天在搭建MySQL MHA  安装MHA node所需的perl模块(DBD:mysql)时遇到了一个小的错误,如果思路不对的话,还是产生不少麻烦. 现梳理记录下来. 问题现象 执行的命令 yum ...

  8. Perl模块管理

    Perl模块管理 perl有自带的模块,还有第三方模块.自带的模块是随perl安装而安装好的,第三方模块需要从CPAN(Comprehensive Perl Archive Network)上下载并安 ...

  9. Linux上安装Perl模块的两种方法

    Linux/Unix下安装Perl模块有两种方法:手工安装和自动安装.第一种方法是从CPAN上下载  您需要的模块,手工编译.安装.第二种方法是联上internet,使用一个叫做CPAN的模块自动完 ...

  10. perl 模块的创建以及制定perl 模块的路径

    1) perl 模块的创建 perl 模块的后缀名为.pm, 其中的内容和一般的perl脚本相同, perl模块中通常放置可重用的函数以及变量, 比如创建一个fasta.pm,里面包含一个统计fast ...

随机推荐

  1. Windows下安装和使用MongoDB

    支持平台:从2.2版本开始,MongoDB不再支持Windows XP.要使用新版本的MongoDB,请用更新版本的Windows系统. 重要:如果你正在使用Windows Server 2008 R ...

  2. Java数据库连接——PreparedStatement的使用

    首先了解Statement和PreparedStatement的区别: 由此可见,一般使用PreparedStatement. 操作数据库SU(Course表),其中Course属性有Cno,Cnam ...

  3. ZBrush中功能强大的插件PaintStop

    PaintStop是ZBrush®3.1的手绘插件,可以比较真实的模拟手绘风格,尤其是用水彩笔刷画水墨风格画.PaintStop插件可供用户免费使用. PaintStop是一款功能强大的插件,已经被添 ...

  4. Ncomputering 安装及参数设置

    1.加域 2.添加用户:系统属性---远程

  5. Node_进阶_5

    Node进阶第五天 为什么mysql不用开mongod –dbpath xx… 答:因为mysql会在”服务”中运行,也就是开机时自动启动并且长久驻扎在内存中了. mongodb其实也能通过设置来设成 ...

  6. (WC2018模拟十二)【FJOI2016集训Day7T3】Xor-Mul棋盘

    是不是应该第100篇博文纪念一下? 题解: 本质简单题...但是我没仔细看这题... 观察它的两个式子,都是xor完再乘以某个数,意味着d数组的每个二进制位对答案的贡献都是独立的,可以每一位分开处理. ...

  7. malloc 和free例程

    #include <stdio.h>#include <stdlib.h>int main(){int a;scanf("%d",&a);int * ...

  8. 怎么给Unity写一个原生的插件

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/50266889 作者:car ...

  9. java里的一些特别值得注意的地方

    return 语句的作用:1.返回值 2.结束某个方法的执行. 局部变量必需要初始化,全局变量系统会默认初始值: 整型数赋默认值为0. 浮点数赋默认值为0.0,boolean赋默认值为false. c ...

  10. Android 开发者不得不面对的六个问题

    一份关于移动应用开发的调查报告显示,Androdid开发者对谷歌的移动操作系统平台的兴趣正在下降.尽管依然有79%的开发者表示对Android “非常感兴趣”,但调查报告显示,一些迹象表明在2012到 ...