【问题标题】:Perl - Error when trying to access two-digit number in array within foreach-loopPerl - 尝试在 foreach 循环中访问数组中的两位数时出错
【发布时间】:2017-05-26 02:20:29
【问题描述】:

我刚开始学习 Perl,偶然发现了一个我无法通过谷歌搜索或阅读我正在学习的书来解决的错误。

我的代码如下所示:

use strict;
use warnings;

my @array = (1, 2, 10);

foreach my $i (@array) {
    print $array[$i-1];
}

如果我有一个仅由一位数组成的数组,这很有效。一旦 foreach 循环达到两位数(在本例中为 10),我就会收到警告说 “在 ... 中使用未初始化的值” 并且循环停止。如果我尝试对数字做任何事情(加法等),也会发生同样的情况,它适用于个位数,但会停止在两位数上。

我现在无法理解这里发生了什么——我猜这与 Perl 存储数组元素的方式有关,但我找不到任何东西,也不知道要搜索什么.

谁能指出我正确的方向?

【问题讨论】:

    标签: perl foreach


    【解决方案1】:

    我不确定你想做什么,但这并没有你认为的那样。

    my @array = (1, 2, 10);
    foreach my $i (@array) {
        print $array[$i-1];
    }
    

    $i 不是像 0、1、2、3 这样的索引...而是$i@array 的每个元素:1、2、10。所以$array[$i-1]$array[0]、@987654327 @,$array[9]@array 没有第九个元素。

    如果你想遍历@array的每个index,循环如下:

    for my $idx (0..$#array) {
        # 0, 1, 2
        print "$idx\n";
    }
    

    如果你想遍历@array的每个元素,循环如下:

    for my $element (@array) {
        # 1, 2, 10
        print "$element\n";
    }
    

    【讨论】:

    • 谢谢大家!我的错误是错误地使用了 foreach 循环——我会再看看这个。太糟糕了,我不能选择多个答案作为正确答案。
    • for my $idx (keys @array)
    【解决方案2】:

    当您使用一本书时,我建议您也使用出色的Perl documentation。以下是答案上下文中的一些示例。在此期间,我还会建议其他一些细节。

    来自Foreach loops (perlsyn page)

    foreach 循环遍历一个普通的列表值,并将标量变量 VAR 依次设置为列表的每个元素。

    因此它从一个数组中挑选每个元素

    use warnings;
    use strict;
    use feature 'say';
    
    my @words = qw(one two three);
    
    foreach my $word (@words) {
        say $word;
    }
    

    say 内置函数类似于 print,但添加了换行符,请参见 feature pragmaqw operator 构建一个“单词”列表(由空格分隔),分配给数组@words。这通常非常方便。

    如果你只想打印一个数组,statement modifiers (perlsyn) 很方便

    say for @array;
    

    这也使用了$_ variable,这是 Perl 中许多东西的默认值。所以上面和say $_ for @array一样。

    如果您希望遍历数组indices,这可以很好地使用range operator

    foreach my $index (0 .. $#array) {
        say "$array[$index] at index $index";
    }
    

    其中$#array@array 的最后一个元素的下标(索引)的特殊符号。在Scalar values in perldata 下找到它。当在foreach 循环中使用范围时,会生成 no 临时数组,因此内存效率很高。虽然它也可以用来制作数组,my @nums = 1..10;


    问题中的代码对元素进行迭代,然后使用它们对数组进行索引。所以它确实print $array[ $element ]。仅当元素恰好是数字并且恰好是该特定数组的有效索引时,这才意外运行。

    【讨论】:

    • 请注意,foreach my $index (0 .. $#array) 不会构建列表,如果@array 很大,则可能会消耗大量内存。相反,它遍历该范围的每个值,因此它的内存效率很高。我相信只有foreach 对范围运算符进行了这种优化; @a = (1..5) 仍然建立一个列表。
    • @Schwern 啊!不错,不知道已编辑,谢谢:)。
    【解决方案3】:

    在 Perl foreach 中,您可以直接从迭代变量访问每个元素,在您的情况下是 $i

    尝试以下方法:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my @array = (1, 2, 10);
    
    foreach my $i (@array) {
        print $i."\n";
    }
    

    注意打印函数调用中的."\n"。不需要,我添加了只是为了美化输出。

    【讨论】:

      【解决方案4】:

      之前的两个答案都很好。我将在混音中添加另一个细微的变化。

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      my @array = (6, 1, 2, 10);
      my $numelements = @array;
      
      for (my $i=0; $i < $numelements; $i++) {
          print "$array[$i]\n";
      }
      

      【讨论】:

      • 虽然这可行,但在 Perl 中通常避免使用 3 arg for 循环。它更慢,更难阅读,并且会引起错误。仅当迭代数组或范围不起作用时才使用它。 $num_elements 是不必要的,$i &lt; @array 更直接。
      • 只是为了展示另一种给猫剥皮的方法。同时举例说明如何获取数组中的元素个数。
      【解决方案5】:

      我想提一下each 函数。您现在可能认为您必须在迭代数组的索引和数组的值之间做出选择:

      遍历索引:

      foreach my $index (0 .. $#array) {
          print "$index\n"; # 0, 1, 2
      }
      

      迭代值:

      foreach my $value (@array) {
          print "$value\n"; # 1, 2, 10
      }
      

      但如果您至少拥有 Perl 5.12,则可以同时拥有两者。使用each函数:

      while (my ($index, $value) = each @array) {
          print "index=$index, value=$value\n";
      }
      

      输出:

      index=0, value=1
      index=1, value=2
      index=2, value=10
      

      例如,如果您想要遍历数组并想要检查上一个或下一个元素,这会很有用。

      【讨论】:

        猜你喜欢
        • 2017-08-20
        • 1970-01-01
        • 2011-05-08
        • 2015-04-28
        • 1970-01-01
        • 1970-01-01
        • 2018-02-17
        • 1970-01-01
        • 2020-10-11
        相关资源
        最近更新 更多