名称冲突问题

假如在sum2.pm中使用require导入了一个代码文件sum1.pm:
#!/usr/bin/env perl use strict; use warnings; use 5.010; require
'/perlapp/sum1.pm'; sub sum { say "sum2: sum()"; } 1;
如果在sum1.pm中也有一个sum子程序:
#!/usr/bin/env perl use strict; use warnings; use 5.010; sub sum { say "sum1:
sum()"; } 1;
那么在运行sum2.pm的时候,将警告子程序重新定义。因为sum2.pm首先编译好自己的sum(),然后在运行期间require
导入文件时,又再次定义sum(),将进行覆盖操作:
Subroutine sum redefined at /perlapp/sum1.pm.....
这样的名称冲突问题,通过声明包来解决。

定义包和访问包属性

要定义一个包,只需要加上关键字package即可。
package PKG_NAME [ VERSION_NUM ];
上面的语句用于声明包,可以带上包版本号,例如package pkg1 0.01;。

例如,在sum1.pm中:
#!/usr/bin/env perl use strict; use warnings; use 5.010; package Sum1; sub sum
{ say "pkg:Sum1,sum()"; } 1;
然后其它文件导入sum1.pm后,就可以使用包名::属性的方式访问sum1.pm中的属性,如子程序。
#!/usr/bin/env perl use strict; use warnings; use 5.010; require
'/perlapp/sum1.pm'; sub sum { say "file: sum2,sum()"; } sum(); # 访问本文件定义的sum子程序
Sum1::sum(); # 访问包Sum1::sum子程序,括号不能少 1;
除了子程序,包中的其它非词法作用域的属性也能被访问,包括:标量、数组、hash、文件句柄。例如:
$Sum1::name; @Sum1::arr;
每个文件都至少定义在一个包内,如果没有显式给定package指令,则这个包默认为main包。所以,访问本程序文件内自身属性的时候可以使用main:: + 属性
的方式。例如在sum2.pm中:
#!/usr/bin/env perl use strict; use warnings; use 5.010; require
'/perlapp/sum1.pm'; sub sum { say "file: sum2,sum()"; } sum(); # 访问本文件定义的sum子程序
main::sum(); # 等价于上一行直接访问sum() Sum1::sum(); # 访问包Sum1::sum子程序,括号不能少 1;
一个文件内多个包

一般来说,一个文件只会定义一个包。但允许一个文件定义通过包。

如下:
package Pkg1; ...code here belong to Pkg1... package Pkg2; ...code here belong
to Pkg2...
定义多个包时,从包1到包2中间的所有属性都属于包1。

例如,在sum1.pm中:
#!/usr/bin/env perl use strict; use warnings; use 5.010; sub sum { #
位于默认的main包 say "pkg:main,sum()"; } package Sum1; # 第一个包 sub sum { # 位于Sum1包 say
"pkg:Sum1,sum()"; } sum(); # 访问的是Sum1包的sum() main::sum(); # 访问的是main包的sum()
package Sum2; # 第二个包 sub sum { # 位于Sum2包 say "pkg:Sum2,sum()"; } sum(); #
访问的是Sum2包的sum() Sum1::sum(); # 访问的是Sum1包的sum() main::sum(); # 访问的是main包的sum() 1;
有一些词语名称总是属于main包的: ARGV、ARGVOUT、ENV、INC、SIG、STDERR、STDIN 以及
STDOUT。有些带有特殊标点符号的名称(如$_,$2, $!),它们也全部属于main。

另外,词法变量是不能使用包名访问的,因为使用包访问的属性,都是"全局"属性。所以,要在代码块中访问全局属性,可以加上包名:
package Sum1; out $var="1234"; sub mysub { my $var; ...$var...; # 访问的是my $var
$Sum1::var; # 访问的是Sum1包中的$var }
如果将一个包声明放进代码块,则出了代码块的域后就消失:
package Sum1; { package main; sub sum { say "in main" } sum(); # 调用main中的sum }
# 退出代码块,重新回到Sum1包 sub sum {code} # 属于Sum1包的sum子程序
包代码块

从perl 5.12开始,支持包代码块:
use v5.12; package pkg1 { ... } package pkg2 { ... }
包代码块相当于词法范围:
package Navigation { my @homeport = (21.283, -157.842); # 属于包 sub get_me_home
{ my @homeport; # 声明词法变量 ... @homeport ... # 访问的是词法变量 ... @Navigation::homeport
... # 访问的是包变量 } ... @homeport ... # 访问的是包变量 }
它等价于:
{
package Navigation;
my @homeport = (21.283, -157.842); # 属于包
sub get_me_home {
my @homeport; # 声明词法变量
... @homeport ... # 访问的是词法变量
... @Navigation::homeport ... # 访问的是包变量
}
... @homeport ... # refers to the package variable
}