我正在使用NetBSD 6.1,Perl v5.18.1和DB_File v1.818。如果我使用each
迭代DB_File绑定的哈希并从哈希中删除每个项目,则不会删除所有项目。这是一个演示问题的脚本:
use strict;
use warnings;
use DB_File;
my $dbfile = "/tmp/foo.db";
! -f $dbfile or unlink($dbfile) or die("unable to delete $dbfile");
my %db;
tie(%db, "DB_File", "/tmp/foo.db", O_RDWR|O_CREAT, 0644);
# add some random records
my @chars = ("0".."9", "a".."f");
for (1..10) {
my ($key, $val);
$key .= $chars[rand(@chars)] for 1..10;
$val .= $chars[rand(@chars)] for 1..32;
$db{$key} = $val;
}
# this doesn't delete everything from the database!
keys(%db); # reset the iterator
while (my ($key, $val) = each(%db)) {
delete $db{$key};
}
foreach (keys(%db)) {
print("\$db{$_} = $db{$_}\n");
}
untie(%db);
当我运行它时,10个记录中的4个(或有时5个)不会被删除:
$db{4a8e5792e0} = 7a4d078a3f0f3cba750cb395fcc3343d
$db{d28e8cb226} = 17af1122f0b94113416693b1c4165954
$db{a3ae4e2e24} = 3c15270cf16601722bd8106b1727dbc2
$db{886c469eb4} = f1496f83f7866d09c9e28aae8e1b62e6
$db{2c53ebd993} = facfe8228240878aac825de4d97ca22b
如果我在Linux(Ubuntu 14.04)系统上运行脚本,那么它总是有效(删除所有记录)。
如果我切换到密钥上的foreach
循环,那么它适用于NetBSD和Linux:
# this always works
foreach (keys(%db)) {
delete $db{$_};
}
我无法找到任何明确表示在通过each
进行迭代时删除的内容并不总是有效。
这是我能找到的:
如果VAR是绑定或其他特殊变量,
foreach
可能无法达到预期效果。
我不确定这是什么意思,但奇怪的是foreach
案例是 工作的地方。
任何插入哈希都可以更改顺序,删除也是如此,但
each
或keys
返回的最新密钥可能会被删除,而不会更改顺序。
对我而言,这意味着在迭代时delete
当前条目是安全的。
documentation for DB_File
在迭代时没有提及删除。
这是问题:
each
?当foreach
没有时,为什么键上的each
会起作用?
答案 0 :(得分:1)
我预感到这种行为是捆绑哈希的限制。似乎无法保证在删除最近获取的密钥时DB_File不会重新进行重新连接。
您还询问了
之间的区别while (my ($key, $val) = each(%db)) {
delete $db{$key};
}
和
foreach (keys(%db)) {
delete $db{$_};
}
在第一种情况下,您在迭代绑定的哈希时干扰绑定的哈希。所以迭代器有可能无法到达所有键。
在第二种情况下,您首先迭代绑定的哈希,以获得完整的键列表。循环遍历完整列表时,您可以保证删除所有条目。