Perl - 从BEGIN块中复制变量值

时间:2016-12-10 13:44:31

标签: perl copy block

我有一个简单的脚本:

our $height = 40;
our $width = 40;

BEGIN {
    GetOptions( 'help' => \$help,           
                'x=i' => \$width,
                'y=i' => \$height) or die "No args.";


    if($help) { 
        print "Some help";   
        exit 0;
    }

    print $width."\n"; #it is 10 when call with script.pl -x 10 -y 10
    print $height."\n"; #it is 10 when call with script.pl -x 10 -y 10

    #some other code which check installed modules

    eval 'use Term::Size::Any qw( chars pixels )';
    if ( $@ ) {
        if ( $@ =~ /Cant locate (\S+)/ ) {
            warn "No modules";
            exit 2;
        }
    }


}

print $width."\n"; #but here is still 40 not 10
print $height."\n";#but here is still 40 not 10

我用2个参数(x和y)调用此脚本,例如:script.pl -x 10 -y 10.但是给定的值不保存在变量$ width和$ height中。我想通过提供参数来改变这些变量。如何复制给定值或将其保存到$width$height?有可能吗?

已编辑 - 我在此示例中添加了一些代码

3 个答案:

答案 0 :(得分:2)

{/ 1}}子句在普通代码之前执行。当您声明BEGIN$height时,在处理选项后将其设置为40

解决方案:处理$width子句之外的选项。

答案 1 :(得分:1)

问题是像our $height = 40等声明/定义分两个阶段执行。 声明在编译时执行,而赋值在运行时完成。这意味着类似

my $x = 0;

BEGIN {
    $x = 1;
}

say $x;

将显示0,因为$x在编译时被声明,并且由于BEGIN块而在编译时设置为1。但它在运行时设置为零。

您需要做的就是将声明/定义更改为声明。这样就不会对BEGIN

所做的赋值进行运行时修改
use strict;
use warnings 'all';
use feature 'say';

my $xx;

BEGIN {
    $xx = 1;
}

say $xx;

输出

1

请注意,不需要ourmy几乎总是可取的。并且请不要使用BEGIN块来执行大量代码:它们应该保留用于在运行时开始之前加载所需模块的准备操作。没有人希望程序输出帮助文本,如果它不能编译,这就是你想要做的。

答案 2 :(得分:0)

运行阶段甚至启动之前,编译阶段中首先执行所有BEGIN块。请参阅此in perlmod并查看this "Effective Perler" article。另一方面,my $x = 1;的声明部分也在编译阶段发生,但赋值在运行时完成。

因此声明了$height$weight,然后处理选项的代码在其BEGIN块中运行,然后然后分配变量{ {1}}。

此外,最好不要在40块中处理选项或进行任何此类大量工作。

以下几种方法可以满足您的需求。

只要您在运行时知道它是否有效,在编译期间加载模块就可以了。因此,在BEGIN块中的eval下加载它,以便您可以(有条件地)设置标记供以后使用。该标志需要在BEGIN块之前声明(没有赋值)。

BEGIN

声明发生在编译时,并且在my $ok_Term_Size_Any; BEGIN { eval 'use Term::Size::Any qw(chars pixels)'; $ok_Term_Size_Any = 1 unless $@; }; # use the module or else, based on $ok_Term_Size_Any 中也是如此 - 在条件BEGIN下也是如此。如果该条件失败(无法加载模块),则不会发生赋值,并且变量保持未定义。因此,它可以用作进一步处理的标志。

注意经过进一步测试后,我遇到了以下方法的问题,并发布了question。随着我发现更多信息,我会更新。

或者,您可以在运行时加载模块,然后继续解析选项。

if not $@语句正好是

use Module qw(LIST);

use。因此,要在运行时检查模块,请在运行之前运行eval该代码

BEGIN {
    require Module;
    Module->import(LIST);
};

不是使用use warnings 'all'; use strict; eval { require Module; Module->import( qw(fun1 fun2 ...) ); }; if ($@) { # Load an alternative module or set a flag or exit ... }; # use the module or inform the user based on the flag (通过必要的错误检查),而是可以使用Try::Tiny,但请注意,这也存在问题。有关选择的讨论,请参阅this post。使用模块而不是eval - 和 - eval的困难原因是resolved in 5.14