10

もちろん、これは必要ありません。ここで何が起こっているのか知りたいだけです。私は何か簡単なものが欠けていますか?Perlのすべてのバージョンでこの動作に依存できますか?)

Perl v5.8.8:

%h = ( 0=>'zero', 1=>'one', 2=>'two' );
while ($k = each %h) {
    $v = delete $h{$k};
    print "deleted $v; remaining: @h{0..2}\n";
}

出力

deleted one; remaining: zero  two
deleted zero; remaining:   two
deleted two; remaining:

man perlfunc$k(each)は、 0が割り当てられたときにwhileループが続く理由を説明していません。コードは、whileループの条件がであるかのように動作します($k = each %h, defined $k)

ループ条件が実際にに変更された場合、実際には 期待どおり($k = each %h, $k)に停止し$k = 0ます。

また$k = 0、次の次の再実装のために停止しeachます。

%h = ( 0=>'zero', 1=>'one', 2=>'two' );
sub each2 {
    return each %{$_[0]};
}
while ($k = each2 \%h) {
    $v = delete $h{$k};
    print "deleted $v; remaining: @h{0..2}\n";
}

出力だけ:

deleted one; remaining: zero  two
4

3 に答える 3

29

スカラーコンテキストで呼び出しeachているため、リストの戻り値のために機能していません。

と同じように

while ($line = <FILE>)

は暗黙の を追加する特殊なケースdefinedであるため、

while ($key = each %hash)

5.8.8 では、op.c の 3760 ~ 3766 行で発生します。

case OP_SASSIGN:
  if (k1->op_type == OP_READDIR
      || k1->op_type == OP_GLOB
      || (k1->op_type == OP_NULL && k1->op_targ == OP_GLOB)
      || k1->op_type == OP_EACH)
    expr = newUNOP(OP_DEFINED, 0, expr);
  break;

これが Perl 5 のすべてのバージョンに当てはまるかどうかはわかりません。

参照: PerlMonksで定義されたものと真であることを while() がテストするのはいつですか。これが Perl ドキュメントのどこで言及されているかを見つけることができません (<FILE>ケースは言及されていますが、ケースはわかりませんeach)。

于 2008-10-21T06:52:50.437 に答える
6

cjm そうですね。このような奇妙なことに遭遇したとき、 B::Deparseを介してコードを実行し、Perl がコードをどのように理解したかを確認することが役立つことが多いことを付け加えたいと思います。-p スイッチを使用して、優先順位の間違いも表示するのが好きです。

$ perl -MO=Deparse,p your_example.plx
(%h) = (0, 'zero', 1, 'one', 2, 'two');
while (defined($k = each %h)) {
    $v = delete $h{$k};
    print "deleted $v; remaining: @h{0..2}\n";
}
your_example.plx syntax OK
于 2008-10-21T20:17:51.797 に答える
0

ありがとう、cjm。何らかの暗黙の a の追加がdefined グロブのように行われていることは明らかでしたが、それが文書化された場所ではありませんでした。少なくとも、その特別な取り扱いが適用される限られたケースを知っています。

しかし、その情報は Perl のソース コードだけでなく、perlfunc のドキュメントにあるはずです!

于 2008-10-21T17:44:31.357 に答える