2

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

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

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

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

我写了一个 tie 模块来处理 COBOL 数据。它需要一个字帖,解析字段,然后将其附加到一个标量/字符串,以便访问/从绑定的哈希将返回/设置字符串中的值。它工作得很好。

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)”而不破坏我的绑定哈希?

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

结语:我将 TieHash 代码修改为,它不是指向外部记录,而是截取散列的“特殊”键,其中是“记录”。因此,当我将记录字符串分配给 $h{'record'} 时,它与在上面的示例中加载 $rec 相同。这是一个更好的解决方案,更独立。它还公开了一个更像 OOP 的接口。

4

3 回答 3

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;
}
于 2012-11-08T21:19:36.983 回答
2

这是一个微妙的点,在文档中很容易忽略,但变量中的循环变量foreach始终是一个新变量,与程序中其他任何地方的任何同名的词法或包变量无关。

来自perlsyn

Foreach 循环

“foreach”循环遍历一个普通的列表值,并依次将变量 VAR 设置为列表的每个元素。如果变量以关键字“my”开头,则它是词法范围的,因此仅在循环中可见。否则,该变量隐含地是循环的局部变量,并在退出循环时恢复其先前的值。如果该变量以前用“my”声明,它使用该变量而不是全局变量,但它仍然本地化到循环中。这种隐式本地化只发生在“foreach”循环中。

(强调补充)。也就是这个小脚本的第3行和第1行声明的$rec无关$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影响绑定哈希的行为(尽管肯定有其他方法可以做到这一点),那么您正在做正确的事情,使用不同的循环变量并$rec在循环内分配给它。

于 2012-11-08T22:36:27.133 回答
0

似乎最好的方法是执行以下操作:

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

不完全是我所希望的优雅,但它似乎奏效了。

于 2012-11-09T16:13:37.657 回答