each函数用以一次一个键字/数值对的方式遍历一个散列。
在散列内部,它以一种看上去是随机的顺序维护它自己的记录。each 可以遍历这个序列是因为每个散列都记得上一次返回的是哪条记录。这个序列的实际的顺序可能在将来的 Perl 版本里会改变,但有一点可以保证,就是 keys(或者 values)函数在同一个(未修改)的散列上生成的顺序是一样的。
每个散列都有一个遍历器,由在该程序里所有的 each,keys,和 values 函数调用共享;该遍历器可以通过从散列里读取所有元素来重置,或者通过计算 keys %hash 或 values %hash 来重置。如果你在遍历散列的过程中删除了元素,那么后果还没有很好的定义:记录可能会被忽略也可能被重复。
因为each函数每次只返回一对键值而不是返回整个列表,所以必须记录上一次的访问位置。
关于遍历器对位置的记录,见下面示例:
#!/usr/bin/perl -w
##############################
use strict;
my %hash = ( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6,);
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
last if($k eq "3");
}
print "----------------------\n";
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
}
执行代码,输出如下:
$ ./test.pl
6 => 6
4 => 4
1 => 1
3 => 3
----------------------
2 => 2
5 => 5
显然,each函数的内部遍历器记录了上次遍历的位置,第二次遍历时从前一次的位置开始。
如果第一次遍历到哈希尾部,则下次开始时会从首部开始遍历:
#!/usr/bin/perl -w
##############################
use strict;
my %hash = ( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6,);
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
}
print "----------------------\n";
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
}
输出如下:
$ ./test.pl
6 => 6
4 => 4
1 => 1
3 => 3
2 => 2
5 => 5
----------------------
6 => 6
4 => 4
1 => 1
3 => 3
2 => 2
5 => 5
如果第一次遍历并没有到达尾部,但使用 keys 重置一次遍历器,下次也会从开头开始遍历,如下:
#!/usr/bin/perl -w
##############################
use strict;
my %hash = ( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6,);
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
last if($k eq "3");
}
print "----------------------\n";
keys %hash;
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
}
输出:
$ ./test.pl
6 => 6
4 => 4
1 => 1
3 => 3
----------------------
6 => 6
4 => 4
1 => 1
3 => 3
2 => 2
5 => 5
这里的遍历器记录的是哈希本身的遍历位置,而不是变量或引用名称,如:
#!/usr/bin/perl -w
##############################
use strict;
my %hash2 = ( x => { 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, });
while(my ($K, $V) = each(%hash2)){
while(my ($k, $v) = each(%$V)){
print "$k => $v\n";
last if($k eq "3");
}
}
print "----------------------\n";
while(my ($K, $V) = each(%hash2)){
while(my ($k, $v) = each(%$V)){
print "$k => $v\n";
}
}
输出如下:
$ ./test.pl
6 => 6
4 => 4
1 => 1
3 => 3
----------------------
2 => 2
5 => 5
显然,这里的遍历二级子哈希时使用了临时变量,但Perl仍然记录了变量的访问位置。
而且,Perl的内部遍历器是全局生效的,而不是像变量名那样只在块作用域中生效。
#!/usr/bin/perl -w
##############################
use strict;
my %hash = ( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6,);
if(1){
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
last if($k eq "3");
}
}
print "----------------------\n";
while(my ($k, $v) = each(%hash)){
print "$k => $v\n";
}
输出:
$ ./test.pl
6 => 6
4 => 4
1 => 1
3 => 3
----------------------
2 => 2
5 => 5
显然,第一次遍历尽管用了块作用域,但仍然影响了第二次遍历的结果。