模块是为我们的程序建立好的块.它提供了子程序,变量和面向对象的类的重用。这一节,我们既能显示了如何建立自己的模块,有能看到如何使用别人已经写好的模块.
标准模块发布
Perl已经自带了很多模块.事实上,最近发布的版本中有50+MB都是模块.1996年10月,Perl 5.003_07有98个模块.今天,也就是2006年初,Perl 5.8.8有了359个.这些都是Perl的一个优点,因为你可以充分利用这些资料在那些复杂的程序中,而不用自己去做这些工作。
通过这本书,我们将认识到Perl自带有哪些模块(更多情况下,是它们开始哪一版本)。我们称这些为"核心模块"或者它们在“标准发布”中。如果你有Perl,你就应该有这些模块。因为在写这本书时我们现在正使用Perl 5.8.7,我们假设这就是当前Perl的版本.
当开发代码时,你可能会思考是否仅仅使用这些"核心模块",以至于你会确定只要他有和你一样的版本的Perl就会有这些模块. 当然我们将避免这种争论,更多的是因为我们非常喜欢CPAN.
使用模块
几乎每一个Perl都有相关的文档,尽管我们还不知道所有幕后的场景是怎么工作,但如果我们想知道如何使用时是真的不需要担心的.这就是为什么那些接口在那儿,而隐藏了细节.
在本机上,我们可以使用perldoc命令来阅读模块文档.我们会给出感兴趣的模块名字,然后写进它相关文档中.
$perldoc File::Basename
NAME
fileparse - split a pathname into pieces
basename - extract just the filename from a path
dirname - extract just the directory from a path
SYNOPSIS
use File :: Basename
($name, $path, $suffix) = fileparse($fullname, @suffixlist);
fileparse_set_fstype($os_string);
$basename = basename($fullname, @suffixlist);
$dirname = dirname($fullname);
我们已经显示了文档中最上面的那部分,也是最重要的.模块文档跟随了Unix man的格式, 以NAME开始,然后是SYNOPSIS部分。
大纲给了我们使用模块的例子,而且如果你能停下理解,看看这个例子,就应该会使用这个模块.这就是说,你可能对大纲中的一些Perl技术和语法还不熟悉,但你可以根据这个例子使得一切都能工作。
现在,因为Perl是程序,函数,面向对象和其他语言类型的混合,所以它的模块也是有各种各样的接口。我们将以不同的形式来使用这些模块,但只要经常查看文档应该是没有问题。
函数接口
为了加载一个模块,我们使用Perl内置的use。现在在这儿我们还不需要了解里面的细节,等到Chapters 10和15我们还会深入讨论它。目前,我们仅仅知道使用模块。下面开始File::Basename. 为了加载它到我们的脚步,我们知道:
use File::Basename;
当我们确实这样做了,File::Basename将引入三个子例程,fileparse,basename,和dirname。从这一点出发,我们能知道:
my $basename = basename( $some_full_name );
my $dirname = dirname( $some_full_name );
就好像我们自己写的basename和dirname子程序,或者好像他们嵌入到Perl函数中。这些程序选择了路径名中的文件名和目录名。例如:
如果$some_full_name是D:/Projects/Island/Rescue/plan7.rtf(假如你是在windows机器上),$basename将是plan7.rtf,$dirname将为D:/Projects/Island/Rescue.
File::Basename模块知道自己所运行的环境类型,因此,它的函数会正确地解析我们所遇到的字符串分隔符。
然而,假设我们已经有了自己的dirname子例程。我们将覆盖File::Basename所提供的定义!如果打开警告的话,我们将看到有信息会显示出来。
选择导入内容
很幸运,我们可以告诉use操作来限制它的行为,从而指定子例程列表名字,这成为导入列表:
use File::Basename ('fileparse', 'basename');
现在模块仅仅给出了两个子例程,剩下了dirname。当然,这种形式看起来很难看,更多的时候我们会看到这样写:
use File::Basename qw(fileparse, basename);
事实上,尽管就是仅仅有一个项目,我们也趋向于使用qw()列表来达到一致性和可维护性;很多时候我们会返回来说:“给我另外一个”,这时候如果已经是qw()列表将变得更简单。
我们已经保护局部的dirname程序,但是如果我们仍然想使用File::Basename's dirname?没问题,我们可以使用完整的包来使用它:
my $dirname = File::Basename::dirname($some_path);
use后面的列表名字不会改变模块中定义的子程序。我们常常可以使用全名而不是导入列表:
my $basename = File::Basename::basename($some_path);
在极端情况下,我们可以导入空列表:
use File::Basename ();
my $base = File::Basename::basename($some_path);
空列表不同于没有列表。空列表是说:“别给我任何东西”,而没有列表是说:“给我默认值”
面向对象接口
相对于File::Basename导入子例程,我们通过File::Spec可以看到另外一种核心模块.首先,File::Spec模块是为了在指定文件上操作而设计的(指定的文件常常是一个文件或目录名,但是这可能是一个存在的文件名--这种情况下,就不再是一个真正的文件名)
不像File::Basename模块,File::Spec有一个面向对象的接口.跟以前一样,我们使用use来加载模块.
use File::Spec;
然后,因为模块有一个面向对象的接口,所以它不能导入任何子例程。而是这个接口可以告诉我们使用类方法来访问模块的功能性。catfile方法就能使用目录分隔符来连接字符串列表。
my $filespec = File::Spec->catfile( $homedir{gilligan},'web_docs','photos','USS_Minnow.gif' );
这次调用File::Spec类中方法catfile将会建立适合本地操作系统的一个路径,并且返回一个单一的字符串.File::Spec模块还提供了其他处理文件路径的方法,你可以阅读perlpoc文档。
一个典型的面向对象的模块:Math::BigInt
因为File::Spec没有对象,所以为了使你对如何使用面向对象模块不惊慌,我们再看另一个核心模块,Math::BigInt,它可以解决本身Perl所不能达到的整数问题。
use Math::BigInt
my $value = Math::BigInt->new(2); #开始于2
$value->bpow(1000); #计算2**1000
print $value->bstr(),"/n"; #输出
如前,模块什么也没有导入。它的整个接口都是使用类方法,像new,根据类名创造类实例,然后调用实例方法,像bpow和bstr。
The Comprehensive Perl Archive Network
<待续>