包与模块 #

一、包(Package) #

1.1 什么是包 #

包是Perl的命名空间机制,用于组织代码和避免命名冲突。

perl
package MyPackage;

sub greet {
    print "Hello from MyPackage!\n";
}

1;

1.2 包切换 #

perl
package main;

$main::var = "main variable";
print $main::var;

package Other;
$Other::var = "other variable";
print $Other::var;

package main;
print $main::var;

1.3 包变量 #

使用 our 声明包变量:

perl
package Counter;

our $count = 0;

sub increment {
    $count++;
    return $count;
}

1;

1.4 完全限定名 #

perl
package main;

$MyPackage::variable = "value";
MyPackage::greet();

二、模块(Module) #

2.1 创建模块 #

创建文件 MyModule.pm

perl
package MyModule;
use strict;
use warnings;

our $VERSION = '1.00';

sub new_function {
    my ($arg) = @_;
    print "Argument: $arg\n";
}

1;

2.2 使用模块 #

perl
use MyModule;

MyModule::new_function("test");

2.3 导出函数 #

使用 Exporter 导出函数:

perl
package MyModule;
use strict;
use warnings;
use Exporter 'import';

our @EXPORT_OK = qw(greet add);
our @EXPORT = qw(greet);

sub greet {
    print "Hello!\n";
}

sub add {
    my ($a, $b) = @_;
    return $a + $b;
}

1;

使用导出的函数:

perl
use MyModule qw(greet add);

greet();
print add(3, 5);

2.4 导入标签 #

perl
package MyModule;
use strict;
use warnings;
use Exporter 'import';

our %EXPORT_TAGS = (
    all => [qw(greet add subtract)],
    math => [qw(add subtract)],
);

our @EXPORT_OK = (@{$EXPORT_TAGS{all}});

sub greet { print "Hello!\n"; }
sub add { return $_[0] + $_[1]; }
sub subtract { return $_[0] - $_[1]; }

1;

使用标签导入:

perl
use MyModule ':all';
use MyModule ':math';

三、use和require #

3.1 use #

use 在编译时加载模块:

perl
use strict;
use warnings;
use MyModule qw(func1 func2);

3.2 require #

require 在运行时加载模块:

perl
require MyModule;
MyModule::greet();

3.3 区别 #

特性 use require
加载时机 编译时 运行时
自动导入
错误处理 编译错误 运行错误

3.4 条件加载 #

perl
if ($need_module) {
    require MyModule;
    MyModule->import(qw(func));
}

四、模块搜索路径 #

4.1 @INC #

@INC 存储模块搜索路径:

perl
print "$_\n" foreach @INC;

4.2 添加搜索路径 #

perl
use lib '/path/to/modules';
use MyModule;

或:

perl
BEGIN {
    unshift @INC, '/path/to/modules';
}

4.3 相对路径 #

perl
use FindBin;
use lib "$FindBin::Bin/lib";

use MyModule;

五、BEGIN和END #

5.1 BEGIN块 #

BEGIN 在编译时执行:

perl
BEGIN {
    print "This runs at compile time\n";
}

5.2 END块 #

END 在程序结束时执行:

perl
END {
    print "This runs at program end\n";
}

5.3 执行顺序 #

perl
print "Main code\n";

BEGIN { print "BEGIN 1\n"; }
BEGIN { print "BEGIN 2\n"; }
END { print "END 1\n"; }
END { print "END 2\n"; }

输出:

text
BEGIN 1
BEGIN 2
Main code
END 2
END 1

六、模块示例 #

6.1 配置模块 #

perl
package Config;
use strict;
use warnings;
use Exporter 'import';

our @EXPORT_OK = qw(get_config set_config);

my %config = (
    host => 'localhost',
    port => 3306,
);

sub get_config {
    my $key = shift;
    return $key ? $config{$key} : %config;
}

sub set_config {
    my %args = @_;
    %config = (%config, %args);
}

1;

6.2 工具模块 #

perl
package Utils;
use strict;
use warnings;
use Exporter 'import';

our @EXPORT_OK = qw(trim capitalize);

sub trim {
    my $str = shift;
    $str =~ s/^\s+|\s+$//g;
    return $str;
}

sub capitalize {
    my $str = shift;
    return ucfirst(lc($str));
}

1;

七、实践练习 #

练习1:创建数学模块 #

perl
package MathUtils;
use strict;
use warnings;
use Exporter 'import';

our @EXPORT_OK = qw(factorial fibonacci is_prime);

sub factorial {
    my $n = shift;
    return 1 if $n <= 1;
    return $n * factorial($n - 1);
}

sub fibonacci {
    my $n = shift;
    return $n if $n <= 1;
    return fibonacci($n - 1) + fibonacci($n - 2);
}

sub is_prime {
    my $n = shift;
    return 0 if $n < 2;
    for my $i (2..int(sqrt($n))) {
        return 0 if $n % $i == 0;
    }
    return 1;
}

1;

使用:

perl
#!/usr/bin/perl
use strict;
use warnings;
use MathUtils qw(factorial fibonacci is_prime);

print "5! = " . factorial(5) . "\n";
print "Fib(10) = " . fibonacci(10) . "\n";
print "Is 17 prime? " . (is_prime(17) ? "Yes" : "No") . "\n";

练习2:创建日志模块 #

perl
package Logger;
use strict;
use warnings;
use Exporter 'import';

our @EXPORT_OK = qw(log_info log_error log_debug);

my $LOG_LEVEL = 'INFO';

sub set_level {
    $LOG_LEVEL = shift;
}

sub log_info {
    my $msg = shift;
    print "[INFO] $msg\n";
}

sub log_error {
    my $msg = shift;
    print "[ERROR] $msg\n";
}

sub log_debug {
    return unless $LOG_LEVEL eq 'DEBUG';
    my $msg = shift;
    print "[DEBUG] $msg\n";
}

1;

八、总结 #

本章学习了:

  • 包的概念和使用
  • 模块的创建和使用
  • use和require的区别
  • Exporter导出函数
  • BEGIN和END块

下一章将学习面向对象编程。

最后更新:2026-03-27