Perl允许你将代码划分成一个或多个可重用的模块。
1.使用关键词package 来定义模块:
2.使用use和require来加载预定义模块
3.使用":"记号来存取包的特定变量和子例程
包的资本知识:
关键词package 标志这一个新的名字空间的开始,在它之后声明的所有的全局标识符(
包括变量名,子例程,文件句柄,打印格式和目录句柄)都将属于这个package.
[root@node01 4]# cat BankAccount.pm
package BankAccount;
$total = 99;
sub deposit {
my $amount=shift;
$total +=$amount;
print "You now have $total dollars
";
}
sub withdraw {
my $amount=shift;
$total -=$amount;
$total=0 if $total<0;
print "You now have $total dollars
";
};
1;
用户定义的全局标识符$total,deposit和withdraw属于包BankAccount.
包的作用域一直延伸到最内存的封闭代码块的结束
[root@node01 4]# cat a3.pl
unshift(@INC,"/root/perl/4");
use BankAccount;
my $total=88;
print "1---$total=$total
";
print $BankAccount::total;
print "
";
[root@node01 4]# perl a3.pl
1---$total=88
99
注意包里的变量必须是全局变量:
包和变量:
在第三章"Typeglob与符号表"中,我曾提到所有的全局名字都位于一个符号表中。
这个有点像一个善意的谎言。
实际上每个包都有它自己的符号表,它们之间互不相同。
那些诸如$|,$_,@ARGV和%ENV之类的内奸变量总是属于包main的。
这些事Perl中唯一真正的全局变量:
符号引用:
加载途径:
[root@node01 4]# perl -e 'print "@INC
";'
/usr/local/perl/lib/site_perl/5.22.1/x86_64-linux /usr/local/perl/lib/site_perl/5.22.1 /usr/local/perl/lib/5.22.1/x86_64-linux /usr/local/perl/lib/5.22.1 .
包的初始化与销毁:
[root@node01 4]# cat a3.pl
unshift(@INC,"/root/perl/4");
use BankAccount;
my $total=88;
print "1---$total=$total
";
print $BankAccount::total;
print "
";
foo**;
[root@node01 4]# perl a3.pl
syntax error at a3.pl line 8, near "**;"
Execution of a3.pl aborted due to compilation errors.
带有语法错误的程序一般根本就不会执行
私有性:
Perl 中的符号是可以任意存取的,信息隐藏并不是强制性的。
联机文档中就形象的描述到:
强制私有性:
你可以在文件范围内使用my操作符来获得绝对安全的私有变量。
符号的导入:
有时为了省去输入的麻烦,你可能需要有选择的将一些符号导入到自己的名字空间中。
例如,你想以sqrt来代替math::sqrt 或者以deposit代替BankAccount::deposit.
use 语句可以让你指定一组可选的用来导入的函数名:
[root@node01 6]# cat a1.pl
use BankAccount('withdraw','deposit');
print withdraw(); #现在你无须使用全能限定就能调用它了
就模块来说,它必须已经准备好向任何use它的程序输出这些名字(也只有这些名字).
[root@node01 6]# cat BankAccount.pm
package BankAccount;
use Exporter;
@ISA=('Exporter'); ##继承Exporter
@EXPORT_OK=('withdraw','deposit');
sub deposit {return "111111111111
";};
sub withdraw {return "222222222222
"};
1;
use和Exporter 是如何工作的:
包的嵌套:
既然所有包在作用域上都是全局性的,因此并不支持包嵌套。
然而你却可以有两个包,一个称做A,另一个称做A::B,
这给出了一种包嵌套的错觉。
当你使用use File时,你会记得Perl将会查找名为File.pm的文件。
当你使用
use Math::Poisson时,Perl将查找名为Math/Poisson.pm(Math为目录,Poisson.pm为文件)
自动加载:
比如说,如果你调用了一个名为Test::func()的函数,而func()并没有在Test模块中定义,
Perl则会自动寻找一个称做Test::AUTOLOAD()的子例程。
随便调用一个函数,如果这个函数不存在就调用autoload函数
如果autoload函数你也没实现,那么就返回函数不存在的错误
名为$AUTOLOAD的变量将被设置为刚才所调用函数的全名("Test::func");
[root@node01 6]# cat Mt.pm
package Mt;
our $AUTOLOAD;
sub AUTOLOAD {
print "$AUTOLOAD=$AUTOLOAD
";
my $program=$AUTOLOAD;
$program=~s/^.*:://g;
print "$program=$program
";
system("$program @_");
};
1;
[root@node01 6]# cat a2.pl
use Mt;
Mt::ls('-lt');
[root@node01 6]# perl a2.pl
$AUTOLOAD=Mt::ls
$program=ls
total 16
-rw-r--r-- 1 root root 195 Apr 22 11:18 Mt.pm
-rw-r--r-- 1 root root 23 Apr 22 11:17 a2.pl
-rw-r--r-- 1 root root 193 Apr 22 06:49 BankAccount.pm
-rw-r--r-- 1 root root 59 Apr 22 06:47 a1.pl
[root@node01 6]# cat a3.pl
foreach $name (keys %main::){
print "$name,
";
};
[root@node01 6]# perl a3.pl
_<perl.c,
_<universal.c,
/,
0,