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(each) 没有解释为什么当$k分配为 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。

另请参阅: while() 何时在 PerlMonks 上测试已定义与真值。我找不到 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 就像 glob 那样进行,但没有记录在案。现在至少我知道这种特殊处理适用的有限情况。

但是信息应该在 perlfunc 文档中,而不仅仅是 Perl 源代码!

于 2008-10-21T17:44:31.357 回答