码上游记

hongjian.xia的个人博客

0%

一个Perl模块的编写方法

起源

最近在工作中需要一些Perl脚本,发现目前项目中脚本的公共功能的复用做得很差,并且现存的复用脚本也只是使用require "/your/path/your_script.pl";简单的引用,并没编写成模块(.pm),安装到@INC目录中。于是就有了这篇博文。在介绍模块编写方法之前,我们先来说说两种加载模块的方式。

模块加载方式

加载模块可以使用requireuse关键字。

两者的区别

  1. require是运行时加载,use是编译时加载。
  2. require可以指定路径,use只会从@INC中查找模块,找不到则会编译失败。
  3. require加载一定在当前命名空间,use可以不污染当前命名空间。

use其实将相当于下面的代码

1
2
require ModuleName;
import ModuleName::(@EXPORT);

模块的编写

使用import函数导出变量和函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Some/Module.pm

package Some::Module;

use strict;
use warnings;
# 由于上面使用了use strict;所以需要加这句,否则编译报错
no strict 'refs';

my $var1 = 513;

sub import {
*{caller() . "::fun1"} = \&fun1;
*{caller() . "::var1"} = \$var1;
}

sub fun1 {
print "I'm fun1.";
}

# 所有模块都需要加,确保加载模块时返回true
1;

# test.pl

use strict;
use warnings;
use 5.010;

# 如果将模块已放到@INC目录下,则不需要下面的代码
BEGIN {
push(@INC, "/your/module/path");
}

use Some::Module;

say $var1;

&fun1();

运行test.pl将会有以下输出

1
2
513
I'm fun1.

import的导出方式,具体讲解参见Advanced Perl Programming(2nd Edition by Simon Cozens) — Chapter 1. Advanced Techniques

使用Exporter模块导出变量和函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Some/Module.pm

package Some::Module;

use strict;
use warnings;

use Exporter;
our @ISA = qw(Exporter);

our @EXPORT = qw($var1 func1);

my $var1 = 513;
sub fun1 {
print "I'm fun1.";
}

# 所有模块都需要加,确保加载模块时返回true
1;

Exporter的导出方式,这里只是使用了最简答的@EXPORT数组,还有其他的使用方法参见Exporter文档

面向对象的模块编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Some/Module.pm
package Some::Module;

use strict;
use warnings;

sub new {
my ($class, @args) = @_;
my $self = {
@args,
name => "Tom",
age => 18
}
bless $self, $class;
}

sub getName {
my $self = shift;
return $selft->{name};
}

sub setName {
my ($self, $name) = @_;
$self->{name} = $name;
}

sub getExt {
my ($self, $ext) = @_;
return $self->{$ext};
}

# test.pl
use strict;
use warnings;
use 5.010;

# 如果将模块已放到@INC目录下,则不需要下面的代码
BEGIN {
push(@INC, "/your/module/path");
}

use Some::Module;

my $obj = Some::Module->new(phone => "3478-1321");
say "Old name: " . $obj->getName();
$obj->setName("Jerry");
say "New Name: " . $obj->getName();
say "Phone: " . $obj->getExt("phone");

运行结果

1
2
3
Old name: Tom
New Name: Jerry
Phone: 3478-1321

如果想学习其他更高级的Perl面向对象编程,可以去了解一下 MoMooMoose等模块。

完结

🎉以上就是模块编写的一些简单总结。