2

問題

NetBSD 6.1、Perl v5.18.1、および DB_File v1.818 を使用しています。を使用して DB_File-tied ハッシュを反復処理し、eachハッシュから各アイテムを削除すると、すべてのアイテムが削除されるわけではありません。問題を示すスクリプトを次に示します。

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) システムでスクリプトを実行すると、常に機能します (すべてのレコードが削除されます)。

キーのループに切り替えると、foreachNetBSD と Linux の両方で機能します。

# this always works
foreach (keys(%db)) {
    delete $db{$_};
}

ドキュメントの内容

via の反復中に削除することが常に機能するとは限らないことを明確に示しているものを見つけることができeachませんでした。

これが私が見つけたものです:

  • ドキュメントにforeachは次のように書かれています:

    foreachVAR が同順位またはその他の特殊な変数である場合、期待どおりの結果が得られない可能性があります。

    これが何を意味するのかはわかりませんが、奇妙なことに、それが機能する場合foreachです。

  • ドキュメントにeachは次のように書かれています:

    ハッシュへの挿入は、削除と同様に順序eachkeys変更する可能性があります。

    私にとって、これdeleteは、反復中に現在のエントリに対して安全であることを意味します。

  • ドキュメントにDB_Fileは、反復中の削除については言及されていません。

質問

この問題はありますか:

  • NetBSD の Berkeley DB 実装のバグが原因ですか?
  • DB_File のバグが原因ですか?
  • の既知の制限each
  • 結合されたハッシュの既知の制限?
  • DB_File 結合ハッシュの既知の制限?

foreachキーが機能eachしないのに機能するのはなぜですか?

4

1 に答える 1

1

私の推測では、動作は結ばれたハッシュの制限です。最近取得したキーを削除するときに DB_File が再ハッシュされないという保証はないようです。

あなたはまた、の違いについて尋ねました

while (my ($key, $val) = each(%db)) {
    delete $db{$key};
}

foreach (keys(%db)) {
    delete $db{$_};
}

.

最初のケースでは、結合されたハッシュを反復処理しながら、結合されたハッシュをいじっています。そのため、反復子がすべてのキーに到達しない可能性があります。

2 番目のケースでは、キーの完全なリストを取得するために、まず関連付けられたハッシュを反復処理します。完全なリストをループすると、すべてのエントリが削除されることが保証されます。

于 2014-05-03T16:42:22.420 に答える