2

このような簡単なコードを実行すると、次のようになります。

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

$xがforeachの@arr配列の各要素に「なる」ため、結果は「11 12131415」になります。十分です。

しかし、これが私のことです...それほど問題ではありません(解決策は簡単ですが、エレガントではありません。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に似たインターフェースを公開します。

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 に答える