Perl:从子目录中的包导出函数?

时间:2013-05-04 21:24:11

标签: perl

我把问题简化为一个小例子。从包中导入/导出函数的方式,我无法理解发生的事情。

此代码有效,我可以从use-myPack.pl。

调用greet()
# myPack.pm
package myPack;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = ('greet');

sub greet {
    printf("Hello!\n");
}

1;

# use-myPack.pl
use myPack qw(greet);
greet();

# Output
PS C:\Users\adam> perl .\use-myPack.pl
Hello!

但是,当我从父目录调用use-myPack.pl并使用::运算符来确保它仍然可以使用myPack时,它找不到名为greet()的函数。

# myPack.pm
package myPack;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = ('greet');

sub greet {
    printf("Hello!\n");
}

1;

# use-myPack.pl
use adam::myPack qw(greet);
greet();

# Output
PS C:\Users> perl .\adam\use-myPack.pl
Undefined subroutine &main::greet called at .\adam\use-myPack.pl line 2.

任何人都可以帮忙解释为什么我可以在第一种情况下拨打greet(),而不是第二种情况?

2 个答案:

答案 0 :(得分:1)

use指令中使用的包名必须与模块的package指令中使用的包相匹配(因为您最终会执行PACKAGE_NAME->import(IMPORT_LIST))。

use Foo::Bar;     with     package Foo::Bar;     = ok
use Bar;          with     package Foo::Bar;     = not ok
use Foo::Bar;     with     package Bar;          = not ok

最简单的选择是将模块更改为使用

package adam::myPack;

允许您继续使用

use adam::myPack qw( greet );

否则,您需要切换到

use myPack qw( greet );

并通过使用

更改库搜索路径(@INC)使Perl找到该模块
use lib 'adam';

use FindBin qw( $RealBin );
use lib "$RealBin/adam";

如果cwd与脚本目录不同,前者有效,而后者则不然。


use lib

的替代方案

如果您调用目录lib而不是adam,则可以使用

use mylib;  # Short for something similar to:
            #   use FindBin qw( $RealBin );
            #   use lib "$RealBin/lib", "$RealBin/../lib";

或者,如果您有一个目录,可以为所有脚本安装模块(例如~/perl5/lib),请在登录脚本中为其设置环境变量PERL5LIB

export PERL5LIB=~/perl5/lib     # sh & bash syntax

答案 1 :(得分:1)

以下是关于packagesmodules之间差异的小型教程。


use My::Package 1.0 (qw'some options');
#                  ↑ no comma

is effectively the same as:

BEGIN{
  # load the <module> if it isn't loaded already
  require My::Package;
  # or
  require 'My/Package.pm';



  # check the version of the <package>
  'My::Package'->VERSION(1.0); # compare against $My::Package::VERSION

  # do extra processing in the <package>
  'My::Package'->import(qw'some options');
}

请注意,只有require处理了module,其他所有语句都处理了同名的package

我/ Package.pm:

package My::Package;
use strict;
use warnings;

our $VERSION = 1.0; # checked by UNIVERSAL::VERSION
# you can actually override VERSION. ( don't though )

# bad example of an import method
sub import{ # called by C<use>
  my( $package, $filename, $line ) = caller;
  print 'you called ', __PACKAGE__, " from $filename at line $line with options @_\n";

  # the following is similar to how Exporter::import works
  no strict 'refs';
  *{ $package.'::exported_sub' } = \&My::Package::Subs::exported_sub;
}

package My::Package::Subs; # <== look another package in the same module

sub exported_sub{...}

如果您使用空列表拨打use,则不会调用import

use My::Package ();
BEGIN{
  require 'My/Package.pm';
}

执行此操作的主要原因是确保在编译时加载module,而不代表调用package执行任何额外操作。


执行此操作时:

require Exporter; # loads module named Exporter
@ISA = qw(Exporter); # inherit C<import> from Exporter.

package上对import的任何方法调用都将由Exporter中的import处理。这包括任何use声明 当然,您不要通过定义自己的importAUTOLOAD方法来覆盖它。



作为旁白

:: operator(否则会出现在perlop中)。
Instead :: and ' are called package separators.

如果::是运营商,则可以执行A :: B :: CA::(B::C),这是(当前)语法错误。