Бесконечная рекурсия для итератора связанного хэша с 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 может быть каким-то особым сигналом фильтра, указывающим конец повторяющихся ключей или тому подобное, и просто не подразумевается как обычный хеш-ключ. По крайней мере, я никуда не кладу.

Другие вопросы по тегам