如何在BEGIN块

时间:2017-09-14 08:39:23

标签: perl

我想在Perl脚本的BEGIN块中使用外部库。 我做的第一个测试是检查我的@INC是否会因为推送一些值而被人员插入:

use strict;
use warnings;

BEGIN {
    push @INC, "d:/external_pm/";

    use Data::Dumper;
    print Dumper @INC;
}

哪个按预期工作并显示:

$VAR1 = 'D:/perl/5163/site/lib';
$VAR2 = 'D:/perl/5163/lib';
$VAR3 = '.';  # I am not sure about this one?!
$VAR4 = 'd:/external_pm/';

现在我想在push

之后立即导入模块
use strict;
use warnings;

BEGIN {
    push @INC, "d:/external_pm/";

    use Data::Dumper;
    print Dumper @INC;
    use ExtScript;
}

以下错误告诉我@INC未更新:
Can't locate ExtScript.pm in @INC (@INC contains: D:/perl/5163/site/lib D:/perl/5163/lib .) at file.pl line 9. BEGIN failed--compilation aborted at file.pl line 9.

为什么@INC没有更新? 我无法导入BEGIN块中的模块?或者是Perl的用途?

2 个答案:

答案 0 :(得分:9)

use语句在编译时执行(特别是在BEGIN阶段),而普通代码稍后运行。让我们看一下这个简化的片段:

BEGIN {
  push @INC, "some/dir";
  use Example;
}

如果我们明确说明所有阶段,那将等同于:

BEGIN {
  push @INC, "some/dir";
  BEGIN { require Example; Example->import() }
}

因此Example模块将在push运行之前导入。

有很多方法可以解决这个问题。

最简单的方法是将 @INC操作放入BEGIN块,然后将模块导入外部:

BEGIN { push @INC, "some/dir" }
use Example;

更好的解决方案是使用lib pragma来处理@INC

use lib "some/dir";
use Example;

但是,存在一个主要区别:use lib会在模块搜索路径的开头放置其他目录,因此您可能会意外覆盖其他模块。 push @INC只会在最后添加目录,如果在其他位置找不到模块,则会作为后备。

答案 1 :(得分:3)

use ExtScript;push @INC之前执行。任

  • use ExtScript;移出BEGIN区块
  • 或将其更改为require / import
  • 或使用-I命令行选项或PERL5LIB env变量。
相关问题