我有一个简单的脚本:
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
?有可能吗?
已编辑 - 我在此示例中添加了一些代码
答案 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
请注意,不需要our
。 my
几乎总是可取的。并且请不要使用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。