Perl: while ($key = every %hash) 不会在 key = 0 处停止

发布于 2024-07-07 09:31:22 字数 1018 浏览 9 评论 0原文

显然我不需要这个; 我只是好奇这里发生了什么。 我失踪了吗 简单的事情吗? 我可以在所有版本的 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 = 每个%h,已定义$k)

如果循环条件实际上改为 ($k = every %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

I don't need this, obviously; I'm just curious about what's going on here. Am I missing
something simple? Can I rely on this behaviour in all versions of 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";
}

outputs

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

man perlfunc (each) does not explain why the
while loop continues when $k is assigned 0.
The code behaves as if the condition on the while loop
were ($k = each %h, defined $k).

If the loop condition is actually changed to
($k = each %h, $k) then it does indeed
stop at $k = 0 as expected.

It also stops at $k = 0 for the following
reimplementation of 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";
}

outputs just:

deleted one; remaining: zero  two

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

方觉久 2024-07-14 09:31:22

您在标量上下文中调用 each,因此由于列表返回值而无法正常工作。

就像

while ($line = <FILE>)

特殊情况下添加隐式定义一样,

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 文档中提到的地方(提到了 情况,但我没有看到 each 情况)。

You're calling each in scalar context, so it's not working because of a list return value.

Just like

while ($line = <FILE>)

is special-cased to add an implicit defined, so is

while ($key = each %hash)

In 5.8.8, that happens in op.c, lines 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;

I'm not sure if this applies to all versions of Perl 5.

See also: When does while() test for defined vs truth on PerlMonks. I can't find where this is mentioned in the Perl docs (the <FILE> case is mentioned, but I don't see the each case).

心如狂蝶 2024-07-14 09:31:22

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

cjm is right. I just want to add that when coming up against strange things like this its often helpful to run your code through B::Deparse to see how Perl understood your code. I like to use the -p switch to show precedence mistakes, too.

$ 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
尸血腥色 2024-07-14 09:31:22

谢谢,cjm。
很明显,某种定义的隐式添加
glob 的情况是这样的,但不是在哪里
记录在案。 现在至少我知道有限的情况
特殊处理适用。

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

Thanks, cjm.
It was clear some kind of implicit addition of a defined
was going on like that for glob but not where it was
documented. Now at least I know the limited cases in which
that special handling applies.

But the information should be in the perlfunc documentation,
not just the Perl source code!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文