Perl - 从 BEGIN 块中复制变量值
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
子句外的选项。
所有 BEGIN
块在 编译阶段 中尽快执行(在它们被解析之后)——在 之前运行阶段甚至开始。看到这个 in perlmod and see this "Effective Perler" article。此外,my $x = 1;
的声明部分也发生在编译阶段,但赋值是在 运行 时完成的。
因此声明了 $height
和 $weight
,然后您的代码在其 BEGIN
块中处理选项 运行s,一旦解释器到达运行 阶段 然后 分配变量 40
,覆盖在 BEGIN
块中分配的任何内容。
因此,一种解决方法是 只在 BEGIN
块之前声明 这些变量,不赋值,并在 40
之后赋值 BEGIN
如果变量仍未定义(我认为是默认值),则阻止。
但是,最好不要在 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
。
注意 请参阅此以了解有关以下方法的细节
或者,在 运行 时加载所有 "tricky" 模块。那么解析选项就没有问题了,现在也可以在运行时间正常完成,在这些模块之前或之后,视情况而定。
use Module qw(LIST);
语句正好是
BEGIN {
require Module;
Module->import(LIST);
};
查看use. So to check for a module at runtime, before you'd use it, run and eval那个代码
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 but note that there are issues with that, too. See this post, also for a discussion about the choice. The hard reasons for using a module instead of eval
-and-$@
have been resolved in 5.14.
而不是使用 eval
(具有必要的错误检查)
问题是declaration/definitions像our $height = 40
等是分两个阶段执行的。 声明在编译时执行,而赋值在运行时完成。这意味着类似
my $x = 0;
BEGIN {
$x = 1;
}
say $x;
将显示 0
,因为 $x
在编译时被 声明 并在编译时设置为 1 因为 BEGIN
块.但它随后在 运行 时被设置为零。
您只需将 declaration/definition 更改为声明即可。这样就不会对 BEGIN
块
所做的赋值进行 运行 次修改
use strict;
use warnings 'all';
use feature 'say';
my $xx;
BEGIN {
$xx = 1;
}
say $xx;
产出
1
注意不需要our
。 my
几乎总是更可取。并且请不要使用 BEGIN
块来执行大量代码块:它们应该保留用于准备操作,类似于在 运行 时间开始之前加载所需的模块。没有人期望程序在无法编译的情况下输出帮助文本,而这正是您正在尝试做的。
我有一个简单的脚本:
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
子句外的选项。
所有 BEGIN
块在 编译阶段 中尽快执行(在它们被解析之后)——在 之前运行阶段甚至开始。看到这个 in perlmod and see this "Effective Perler" article。此外,my $x = 1;
的声明部分也发生在编译阶段,但赋值是在 运行 时完成的。
因此声明了 $height
和 $weight
,然后您的代码在其 BEGIN
块中处理选项 运行s,一旦解释器到达运行 阶段 然后 分配变量 40
,覆盖在 BEGIN
块中分配的任何内容。
因此,一种解决方法是 只在 BEGIN
块之前声明 这些变量,不赋值,并在 40
之后赋值 BEGIN
如果变量仍未定义(我认为是默认值),则阻止。
但是,最好不要在 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
。
注意 请参阅此
或者,在 运行 时加载所有 "tricky" 模块。那么解析选项就没有问题了,现在也可以在运行时间正常完成,在这些模块之前或之后,视情况而定。
use Module qw(LIST);
语句正好是
BEGIN {
require Module;
Module->import(LIST);
};
查看use. So to check for a module at runtime, before you'd use it, run and eval那个代码
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 but note that there are issues with that, too. See this post, also for a discussion about the choice. The hard reasons for using a module instead of eval
-and-$@
have been resolved in 5.14.
eval
(具有必要的错误检查)
问题是declaration/definitions像our $height = 40
等是分两个阶段执行的。 声明在编译时执行,而赋值在运行时完成。这意味着类似
my $x = 0;
BEGIN {
$x = 1;
}
say $x;
将显示 0
,因为 $x
在编译时被 声明 并在编译时设置为 1 因为 BEGIN
块.但它随后在 运行 时被设置为零。
您只需将 declaration/definition 更改为声明即可。这样就不会对 BEGIN
块
use strict;
use warnings 'all';
use feature 'say';
my $xx;
BEGIN {
$xx = 1;
}
say $xx;
产出
1
注意不需要our
。 my
几乎总是更可取。并且请不要使用 BEGIN
块来执行大量代码块:它们应该保留用于准备操作,类似于在 运行 时间开始之前加载所需的模块。没有人期望程序在无法编译的情况下输出帮助文本,而这正是您正在尝试做的。