如何在不更改循环变量地址的情况下使用foreach迭代数组?

时间:2012-11-08 21:08:24

标签: perl

当我运行这样一段简单的代码时:

my @arr=(1..5);
my $x;
foreach $x (@arr) {
    $x+=10;
}
print "@arr";

结果是“11 12 13 14 15”,因为$ x“变成”foreach中@arr数组中的每个元素。够了。

但这是我的事情......不是一个问题(解决方案很简单,但不优雅,我希望我的perl尽可能优雅)。

我写了一个用于处理COBOL数据的tie模块。它需要一个副本,解析字段,然后将其附加到标量/字符串,以便访问/来自绑定的散列将返回/设置字符串中的值。它运作得非常好。

my %h,$rec;
my $cb=<<END;
       01 CH-RECORD.
          05 JOB-NUM PIC X.
          05 FILLER  PIC X(76).
          05 REC-TYPE PIC X(2).
END
tie %h, 'COBOLDataTie',$cb,\$rec; #tie the hash to the record via the copybook

从那里,我可以将COBOL记录移动到$ rec并使用%h哈希访问COBOL字段。

同样,这完美无缺。但问题来自于我想要迭代一堆COBOL记录。因此,如果在上面的代码之后我有类似的东西:

foreach $rec (@arr) {
    print "Job is ",$h{'JOB-NUM'},"\n";
}

它不起作用,因为foreach实际上改变了$ rec的位置,这打破了它的关系。我最终不得不做这样的事情:

foreach (@arr) {
    $rec=$_;
    print "Job is ",$h{'JOB-NUM'},"\n";
}

我有什么方法可以做“foreach $ rec(@arr)”而不是打破我的捆绑哈希?

(在任何人说之前,是的,我知道这需要一个很好的面向对象的解决方案......有一天我会做到这一点;我只需要先找一些时间)

EPILOGUE:我修改了TieHash代码,而不是指向外部记录,它截取哈希的“特殊”键,其中包括“记录”。因此,当我将记录字符串分配给$ h {'record'}时,它与上面示例中的加载$ rec相同。这是一个更好的解决方案,更加独立。它还暴露出更像OOP的界面。

3 个答案:

答案 0 :(得分:2)

您决定创建的界面是“分配到$rec,然后通过%h”访问字段。因此,这正是您需要做的。

for (@arr) {
    $rec = $_;
    print "Job is $h{'JOB-NUM'}\n";
}

当然看起来很奇怪,但那是因为它很奇怪。这会更合理:

for (@arr) {
    my $h = parse($cb, $_);
    print "Job is $h->{'JOB-NUM'}\n";
}

你甚至可以用最小的改变来做到这一点:

sub parse {
    my ($cb, $rec) = @_;
    tie my %h, 'COBOLDataTie', $cb, \$rec; 
    return \%h;
}

答案 1 :(得分:2)

这是一个微妙的点,在文档中很容易被忽略,但foreach变量中的循环变量始终是一个新变量,与任何名称相同的词汇或包变量无关否则在程序中。

来自perlsyn

  

Foreach循环

     

“foreach”循环遍历正常列表值并设置          变量VAR依次是列表的每个元素。如果变量          之前是关键字“my”,然后它是词法范围的,并且是          因此仅在循环内可见。否则,变量是          隐含地循环本地并在退出时重新获得其原值          循环。如果变量先前使用“my”声明,则使用          该变量而不是全局变量,但它仍然是本地化的          循环。这种隐式本地化只发生在“foreach”循环中。

(重点补充)。也就是说,这个小脚本第3行中的$rec与第1行中声明的$rec无关

1: my $rec = 'foo';
2: print $rec;                       # 'foo'
3: foreach $rec (@some_list) {
4:     print $rec;                   # something else
5: }
6: print $rec;                       # 'foo' again

因此,如果您想使用\$rec来影响绑定哈希的行为(尽管还有其他方法可以做到这一点),那么您正在做正确的事情来使用不同的循环变量并分配{{ 1}}在循环内部。

答案 2 :(得分:0)

似乎最好的方法是做一些事情:

for (my $i=0;($rec=$arr[$i], $i<@arr);$i++) {

不完全是我希望的优雅,但似乎有效。