在列表上下文中对哈希调用时,返回一个由哈希的下一个元素的键和值组成的 2 元素列表。仅在 Perl 5.12 及更高版本中,它还将返回数组的下一个元素的索引和值,以便你可以对其进行迭代;较早版本的 Perl 将其视为语法错误。在标量上下文中调用时,仅返回哈希中的键(而不是值),或数组中的索引。
哈希条目以看似随机的顺序返回。实际的随机顺序特定于给定的哈希;对两个哈希执行完全相同的操作系列可能会导致每个哈希的顺序不同。对哈希的任何插入都可能更改顺序,删除也会更改顺序,但 each
或 keys
返回的最近的键可以在不更改顺序的情况下被删除。只要给定的哈希未修改,你就可以依赖 keys
、values
和 each
重复返回彼此相同的顺序。有关哈希顺序随机化的详细信息,请参阅 perlsec 中的“算法复杂度攻击”。除了此处提供的保证之外,Perl 哈希算法和哈希遍历顺序的确切详细信息可能会在 Perl 的任何版本中发生更改。
在 each
从哈希或数组返回所有条目后,对 each
的下一次调用会在列表上下文中返回空列表,在标量上下文中返回 undef
;该调用后的下一次调用重新启动迭代。每个哈希或数组都有自己的内部迭代器,可通过 each
、keys
和 values
访问。当 each
已达到如上所述的结尾时,迭代器会隐式重置;可以通过对哈希或数组调用 keys
或 values
,或在列表上下文中引用哈希(但不是数组)来显式重置。如果你在迭代哈希时添加或删除其元素,则对迭代器的影响是未指定的;例如,条目可能会被跳过或重复——所以不要这样做。例外:始终可以安全地删除 each
最近返回的项目,因此以下代码可以正常工作
while (my ($key, $value) = each %hash) {
print $key, "\n";
delete $hash{$key}; # This is safe
}
绑定的哈希可能具有与 perl 的哈希实现不同的排序行为。
each
使用的迭代器附加到哈希或数组,并在应用于同一哈希或数组的所有迭代操作之间共享。因此,在单个哈希或数组上对 each
的所有使用都会推进相同的迭代器位置。对 each
的所有使用也会受到对同一哈希或数组使用 keys
或 values
或在列表上下文中引用哈希(但不是数组)重置迭代器的影响。这使得基于 each
的循环非常脆弱:很容易在迭代器已经部分遍历对象的情况下到达这样的循环,或者在执行循环体期间意外地破坏迭代器状态。在开始循环之前显式重置迭代器很容易,但是没有办法将循环使用的迭代器状态与循环体期间可能执行的任何其他内容使用的迭代器状态隔离开来。为了避免这些问题,请使用 foreach
循环,而不是 while
-each
。
这扩展到对匿名哈希或数组构造函数的结果使用 each
。每次都会创建一个新的底层数组或哈希,因此每次都会从头开始迭代,例如
# loops forever
while (my ($key, $value) = each @{ +{ a => 1 } }) {
print "$key=$value\n";
}
这会像 printenv(1) 程序一样打印出你的环境,但顺序不同
while (my ($key,$value) = each %ENV) {
print "$key=$value\n";
}
从 Perl 5.14 开始,一项实验性功能允许 each
采用标量表达式。此实验已被视为不成功,并已从 Perl 5.24 中移除。
从 Perl 5.18 开始,你可以在 while
循环中使用一个裸 each
,它将在每次迭代中设置 $_
。如果将 each
表达式或将 each
表达式显式赋值给标量用作 while
/for
条件,则该条件实际上会测试表达式的值是否已定义,而不是其常规真值。
while (each %ENV) {
print "$_=$ENV{$_}\n";
}
为了避免让使用早期版本 Perl 并遇到神秘语法错误的代码潜在用户感到困惑,请将此类内容放在文件的顶部,以表明你的代码仅适用于较新版本的 Perl
use v5.12; # so keys/values/each work on arrays
use v5.18; # so each assigns to $_ in a lone while test