Perl的每个功能都值得使用吗?

Eug*_*ash 12 perl hash each iterator

perldoc -f我们读到:

有一个单一的迭代器每个散列,由所有共享each,keys以及values在程序的函数调用; 它可以通过读取散列中的所有元素或通过评估keys HASH或重置来重置values HASH.

当您离开包含范围的范围时,不会重置迭代器each(),这可能会导致错误:

my %h = map { $_, 1 } qw(1 2 3);
while (my $k = each %h) { print "1: $k\n"; last }
while (my $k = each %h) { print "2: $k\n"       }
Run Code Online (Sandbox Code Playgroud)

输出:

1: 1
2: 3
2: 2
Run Code Online (Sandbox Code Playgroud)

这种行为的常见解决方法是什么?它each一般值得使用吗?

dra*_*tun 10

只要您意识到这一点,我认为值得使用.当您在迭代中同时需要键和值时,它是理想的:

while (my ($k,$v) = each %h) {
    say "$k = $v";
}
Run Code Online (Sandbox Code Playgroud)

在您的示例中,您可以通过添加keys %h;如下来重置迭代器:

my %h = map { $_ => 1 } qw/1 2 3/;
while (my $k = each %h) { print "1: $k\n"; last }
keys %h;  # reset %h
while (my $k = each %h) { print "2: $k\n" }
Run Code Online (Sandbox Code Playgroud)

从Perl 5.12开始,each也允许在数组上进行迭代.


Eth*_*her 8

我觉得each这样的习语非常方便:

my $hashref = some_really_complicated_method_that_builds_a_large_and_deep_structure();
while (my ($key, $value) = each %$hashref)
{
    # code that does stuff with both $key and $value
}
Run Code Online (Sandbox Code Playgroud)

对比这个代码:

my $hashref = ...same call as above
foreach my $key (keys %$hashref)
{
    my $value = $hashref->{$key};
    # more code here...
}
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,无论是$key$value立即可用的循环体.在第二种情况下,$value必须先取出.另外,密钥列表$hashref可能非常庞大,占用内存.这有时是一个问题.each不会产生这样的开销.

但是,缺点each并不是很明显:如果早期从循环中止,则不会重置散列的迭代器.另外(我觉得这个更严重的,甚至不可见):你不能打电话keys(),values()或其他each()从这个循环中.这样做会重置迭代器,你会在while循环中失去你的位置.while循环将永远持续,这绝对是一个严重的错误.


jro*_*way 8

each使用过于危险,许多风格指南都禁止使用它.危险在于如果循环each在散列结束之前中止,则下一个循环将从那里开始.这可能导致非常难以重现的错误; 程序的一部分的行为将取决于程序中完全不相关的其他部分. 可能使用each正确,但是可能使用您的哈希(或hashref;它是相同的)所写的每个模块怎么样?

keys并且values总是安全的,所以只需使用它们. keys无论如何,使得以确定性顺序遍历散列更容易,这几乎总是更有用.(for my $key (sort keys %hash) { ... })

  • 无论是否全球都无所谓.即使是类的私有属性也容易受到这个问题的影响.任何返回对哈希的引用的内容都会受到影响. (3认同)

yst*_*sth 7

每个都不仅值得使用,如果你想要遍历所有对内存来说太大的连接哈希,那么它几乎是强制性的.

在开始循环之前,void-context keys()(或值,但一致性很好)是唯一必需的"解决方法"; 你有什么理由寻找其他解决方法吗?