Бесконечная рекурсия для итератора связанного хэша с perldbmfilter для filter_fetch_key
У меня есть Perl-связанный хеш, который использует SDBM_File
модуль и мне нужно сделать некоторые преобразования кодировки символов при сохранении или получении значений.
Я следовал за документацией perldbmfilter
и в целом это работает: я получаю результаты из хэша, правильно закодированного, как и ожидалось, и он сохраняет значения байтов для моей кодировки в файле, который я проверяю с помощью шестнадцатеричного редактора.
Не работает какая-либо итерация по всем элементам хэша, либо с использованием keys
, или же each
или такие вещи, как Data::Dumper
или даже простая операция копирования в другой хеш.
То, что я всегда получаю, это бесконечная рекурсия. Кажется, что итератор никогда не доходит до конца, и если я использую each
и выведите повторенные значения, они повторяются.
Я выследил проблему до использования filter_fetch_key
и преобразование кодировки я там делаю. Если я закомментирую filter_fetch_key
или если я поменяю метод фильтра, чтобы сделать просто return shift
, затем итерация снова работает. Любой из них решает мою проблему, но мне нужно использовать filter_fetch_key
отправить вызывающему абоненту правильно закодированные строки.
$dbm->filter_fetch_key (sub { $_ = $self->_normalizeCharset($_); });
sub _normalizeCharset
{
my $self = shift || Carp::croak(...);
#return shift;
return ...::windows2utf(shift);
}
Если я раскомментирую return shift
итерация работает; но прокомментировал как выше это не так. Я думаю, что есть что-то делать, что происходит с $_
но я понятия не имею, как windows2utf
просто копирует данные и выполняет некоторую кодировку символов. Это работает одинаково для хранения ключей и значений и даже для извлечения значений. Только ключи являются проблемой, и только если я делаю итерацию, а не если я напрямую запрашиваю конкретные ключи.
Есть намеки на то, что я делаю не так?
Есть нить на Perlmonks
также.
1 ответ
Я обнаружил проблему: во время испытаний я понял, что filter_fetch_key
вызывает мою функцию один раз со значением ключа undef
и мои функции возвращают пустую строку для удобства в этом случае. Похоже, это и является причиной бесконечного цикла, я думаю, что кто-то захочет добавить эту пустую строку в качестве нового ключа к хешу по какой-то причине и столкнется с проблемами с каким-то итератором, который становится недействительным или тому подобное. Интересно то, что изменения в ключах должны быть в полном порядке, потому что один из примеров в документации именно об этом, и мои тесты показывают, что я могу заменить каждый ключ, кроме undef
тот, который мне нравится, я могу создать совершенно новые ключи, добавив, например, __. Нет проблем, только если я не вернусь undef
за undef
Я получаю бесконечный цикл. Первая версия следующего метода работает, вторая - нет.
sub _normalizeCharset
{
my $self = shift || Carp::croak(...);
my $value = shift;
my $key = shift || 0;
return undef unless (defined($value));
#return '' unless (defined($value));
$value = "__$value" if ($key);
return ...::windows2utf($value);
}
sub _normalizeCharset
{
my $self = shift || Carp::croak(...);
my $value = shift;
my $key = shift || 0;
#return undef unless (defined($value));
return '' unless (defined($value));
$value = "__$value" if ($key);
return ...::windows2utf($value);
}
Похоже undef
может быть каким-то особым сигналом фильтра, указывающим конец повторяющихся ключей или тому подобное, и просто не подразумевается как обычный хеш-ключ. По крайней мере, я никуда не кладу.