名称冲突问题

假如在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
}

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!