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也允许在数组上进行迭代.
我觉得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循环将永远持续,这绝对是一个严重的错误.
each使用过于危险,许多风格指南都禁止使用它.危险在于如果循环each在散列结束之前中止,则下一个循环将从那里开始.这可能导致非常难以重现的错误; 程序的一部分的行为将取决于程序中完全不相关的其他部分. 您可能使用each正确,但是可能使用您的哈希(或hashref;它是相同的)所写的每个模块怎么样?
keys并且values总是安全的,所以只需使用它们. keys无论如何,使得以确定性顺序遍历散列更容易,这几乎总是更有用.(for my $key (sort keys %hash) { ... })
每个都不仅值得使用,如果你想要遍历所有对内存来说太大的连接哈希,那么它几乎是强制性的.
在开始循环之前,void-context keys()(或值,但一致性很好)是唯一必需的"解决方法"; 你有什么理由寻找其他解决方法吗?
| 归档时间: |
|
| 查看次数: |
3831 次 |
| 最近记录: |