[英]Perl - copy variables value out of BEGIN 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
? 是否可以?
编辑- 我在这个例子中添加了一些代码
BEGIN
子句在正常代码之前执行。 声明$height
和$width
,在处理选项后将它们设置为 40。
解决方案:处理BEGIN
子句之外的选项。
问题是像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
请注意,不需要our
. my
的几乎总是可取的。 并且请不要使用BEGIN
块来执行重要的代码块:它们应该保留用于类似于在运行时开始之前加载所需模块的准备操作。 没有人希望程序在无法编译时输出帮助文本,而这正是您想要做的。
所有BEGIN
块都在编译阶段执行,尽快(在它们被解析之后)——甚至在运行阶段开始之前。 在 perlmod 中查看此内容并查看这篇“Effective Perler”文章。 另外, my $x = 1;
的声明部分my $x = 1;
也发生在编译阶段,但分配是在运行时完成的。
因此声明了$height
和$weight
,然后处理选项的代码在其BEGIN
块中运行,一旦解释器进入运行阶段,则变量被分配40
,覆盖在该BEGIN
块中分配的任何内容。
因此,一种解决方法是仅在BEGIN
块之前声明这些变量,而无需赋值,如果变量仍未定义(我假设为默认值),则在BEGIN
块之后分配40
。
但是,最好不要在BEGIN
块中处理选项或进行任何此类大量工作。
这里有一些其他方法可以满足您的需求。
在编译期间加载模块很适合您的目的,只要您在运行时知道它是否有效。 因此,在BEGIN
块中的eval
下按您的方式加载它,以便您可以设置一个标志供以后使用(有条件地)。 这个标志需要在那个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
也是如此 - 在条件if not $@
。 如果该条件失败(无法加载模块),则赋值不会发生并且变量保持未定义状态。 因此,它可以用作进一步处理中的标志。
另外:虽然没有显示其余的代码,但我无法想象需要our
; 用my
代替。
注意请参阅此问题以了解有关以下方法的细微之处
或者,在运行时加载所有“棘手”模块。 然后解析选项没有问题,现在可以在运行时正常完成,在这些模块之前或之后,视情况而定。
use Module qw(LIST);
声明正是
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而不是使用eval
(带有必要的错误检查),但请注意,这也存在问题。 请参阅此帖子,也可了解有关选择的讨论。 使用模块而不是eval
-and- $@
的硬性原因已 在 5.14 中解决。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.