小型调试问题,由于某些原因我无法解决。考虑以下代码:
use warnings;
my $flag = 0;
foreach my $i (0..scalar(@ARGV)) {
$data{$OPTION} .= $ARGV[$i]." " if($flag);
$flag = 1 if($ARGV[$i] =~ /$OPTION/);
undef $ARGV[$i] if($flag);
}
我收到以下两个警告:
Use of uninitialized value within @ARGV in concatenation (.) or string at line 4
Use of uninitialized value in pattern match (m//) at line 5
我得到的原因是,我未定义@ARGV
的某个值,然后它试图对其进行检查。
我这样做的原因是因为我想在使用@ARGV
模块(使用此数组)之前先“剪切” GetOpt
的某些数据。
如何解决?
答案 0 :(得分:3)
让我们对这些评论进行一些扩展。
想象@ARGV
包含四个元素。它们将具有索引0、1、2和3(因为Perl中的数组从零开始)。
您的循环如下所示:
foreach my $i (0..scalar(@ARGV)) {
您想访问@ARGV
中的每个元素,因此您使用范围运算符(..
)生成所有这些索引的列表。但是scalar @ARGV
返回@ARGV
中的元素数,即4。所以您的范围是0 .. 4.而且$ARGV[4]
处没有值-因此您会收到“未定义值”警告(当您尝试读取数组末尾时)。
一种更好的方法是使用$#ARGV
而不是scalar @ARGV
。对于Perl中的每个数组变量(例如@foo
),您还将获得一个变量(称为$#foo
),该变量包含数组中的最后一个索引号。在我们的例子中,它是3,并且您的范围(0 .. $#ARGV
)现在包含整数0 .. 3,并且您不再尝试读取数组末尾的内容,并且不会收到“未定义值”警告。
我建议还有其他改进。在循环内部,您仅使用$i
来访问@ARGV
中的元素。它仅在$ARGV[$i]
之类的表达式中使用。在这种情况下,最好跳过中间人并遍历数组中的元素而不是索引。
我的意思是您可以这样编写代码:
foreach my $arg (@ARGV) {
$data{$OPTION} .= $arg . " " if($flag);
$flag = 1 if($arg =~ /$OPTION/);
undef $arg if($flag);
}
我认为这更容易理解。