如何创建和加载perl模块,深入理解perl模块
加载模块
模块有两种类型:传统模块和面向对象模块。
传统模块定义子例程和变量,供调用者导入和使用。
面向对象模块相当于类定义,可以通过方法调用来访问。
通过如下命令加载模块:
1.1 编译阶段加载模块使用use
use MODULE;
等价于:
BEGIN {
require MODULE;
MODULE->import();
}
有些模块在其导入列表中提供了额外的功能,这个列表将成为import
的参数表。
use MODULE LIST;
相当于:
BEGIN {
require MODULE;
MODULE->import(LIST);
}
use查询模块的过程
- 加载模块发生在编译阶段,所以模块中的所有代码都在编译阶段运行。
use
将::
转换为/
,以MODULE为文件名在末尾追加.pm
。- 在
@INC
中查找这个组合成的模块文件。 - 一旦加载,被找到的文件路径会存入
%INC
,之后可以重用。 - 所以,对
@INC
的所有修改要在use之前发生,
import的使用
- import把符号(子例程和变量)放在当前命名空间中,从而使编译单元的其余部分可以访问这些符号。
- 导入默认列表
use File::Basename;
- 导入指定符号
use Hash::Util qw(lock_keys);
- 不希望任何导入
use MODULE ();
- 使用一个模块的某个特定版本(或更新版本)
use MODULE VERSION LIST;
## 正常情况下,任何大于或等于VERSION的版本都是可以的,不能指定版本或版本范围。
## 通常指定版本(或更新版本)是为了避免之前版本中的已知的问题。
1.2 运行阶段加载模块使用require
如果希望在运行阶段加载模块,即直到运行一个真正需要这个模块的子例程时才包含该模块,这种情况使用require
。
require MODULE;
require
也可以直接加载文件,要使用正确的路径分隔符(导致问题:不可移植)
require FILE;
require 'Animal/Mammal/HoneyBadger.pm';
1.3 使用no
use反过来就是no。no调用unimport。语法和use一样
no MODULE;
no MODULE LIST;
no MODULE VERSION;
no MODULE VERSION LIST;
no
一般用于临时性的目的,比如短时间希望某些符号能够使用,或者短时间不需要某些特性。
## 先使用Moose模块建立对象,在package末尾取消Moose的导入
package Person;
use Moose;
has "first_name" => (is => "rw", isa => "Str");
has "last_name" => (is => "rw", isa => "Str");
sub full_name {
my $self = shift;
$self–>first_name . " " . $self–>last_name
}
no Moose; # keywords are removed from the Person package
or
## 使用符号引用的特性
$a = "this is a";
{
no strict "refs";
print ${"a"};
}
创建模块
2.1 命名规则
NOTE:
- 一旦选择了一个模块名,就不能更换,毕竟不能让用户更新代码去更新模块名。
- 模块名应当首字母大写。program才能使用全部小写的名字。
2.2 创建传统模块
package Proj_utils 1.001; ##包名和版本
require Exporter; ## 引入Exporter模块
our @ISA = qw(Exporter); ## 继承Exporter模块
@EXPORT = qw(&getString &getMode); ## 默认导出的模块
@EXPORT_OK = qw($string $mode); ## 可以根据请求导出的模块
%EXPORT_TAGS = ( ## 可以作为标签组导出的模块
string => [qw($string &getString)],
mode => [qw($mode &getMode)],
);
our $string = "this is a module";
sub getString {
return $string;
}
our $mode = "traditional mode";
sub getMode {
return $mode;
}
1;
2.3 创建面向对象模块
面向对象的模块规则比较简单,它与用户的通信不多,只要定义好一个对象就行。
package Proj_utils 1.002;
sub new { ## 定义一个对象
my ($class, @args) = @_;
my $self = {
string => "this is a oo module",
mode => "oo",
};
bless $self, $class;
}
sub getString { ## 对象方法
my $class = shift;
$class->{string};
}
sub getMode { ## 对象方法
my $class = shift;
$class->{mode};
}
1;
2.4 模块的导出规则
用use加载一个模块时,这个模块通常会提供一些变量或函数允许你的程序访问。
这种从模块导出符号的行为(导入到程序),被称为polluting命名空间。
大多数模块使用Exporter模块完成这个工作。
package A;
## 大多数模块的开头(结合加载模块一节理解'import'函数的作用)
require Exporter; ## 加载Exporter模块
@ISA = qw (Exporter); ## 继承Exporter,获取'import'方法
############或者这样的开头
#### use Exporter qw(import); ## 获取'import'方法
####
############或者这样的开头
#### @ISA = qw(Exporter) ## 必须继承Exporter
#### sub import { ## 重写import
#### A->export_to_level(1, @_); ## 使用export_to_level手动实现import功能
#### }
############################
######### 定义函数和变量
sub func {}
sub func_sm {}
our @arr = qw(a b c);
our $variable = "a variable";
###### 导出符号
@EXPORT = qw(&func $variable); ## 默认导出
@EXPORT_OK = qw(@arr &func_sm); ## 根据请求导出
%EXPORT_TAGS = ( ## 作为标签组导出
var => [qw($variable @arr)],
fun => [qw(&func &func_sm)],
);
1;
2.5 版本检查
在模块中定义$VERSION
变量来定义模块的版本,使用模块的程序就可以确保这个模块足够新。
use Module 3.14; ## 3.14或更新
use Module v3.0.4; ## 3.0.4或更新
使用VERSION()
查看模块的版本,此函数继承自UNIVERSAL。
print Module->VERSION();
在模块中定义版本
package Module;
our $VERSION = '1.0.1';
或者
package Module v1.0.1;