Что `$ hash {$ key} | = {}` делает в Perl? - PullRequest
3 голосов
/ 01 октября 2008

Я боролся с каким-то Perl, который использует хеш-ссылки.

В итоге оказалось, что моей проблемой была строка:

$myhash{$key} |= {};

То есть «присваивать $ myhash {$ key} ссылку на пустой хеш, если оно уже не имеет значения».

Разыменование этого и попытка использовать его в качестве ссылки на хэш, однако, привело к ошибкам интерпретатора при использовании строки в качестве ссылки на хэш.

Изменение на:

if( ! exists $myhash{$key}) {
  $myhash{$key} = {};
}

... заставил вещи работать.

Так что у меня нет проблемы . Но мне любопытно, что происходит.

Может кто-нибудь объяснить?

Ответы [ 4 ]

16 голосов
/ 01 октября 2008

Perl имеет сокращенные операторы присваивания. Оператор ||= часто используется для установки значений по умолчанию для переменных из-за возможности Perl иметь логические операторы, возвращающие последнее оцененное значение. Проблема в том, что вы использовали |=, который является побитовым или вместо ||=, который является логическим или.

Начиная с Perl 5.10, вместо него лучше использовать //=. // является логическим определенным оператором «или» и не терпит неудачу в угловом случае, когда текущее значение определено, но имеет значение false.

15 голосов
/ 01 октября 2008

Причина, по которой вы видите ошибку при использовании строки в качестве хеш-ссылки, заключается в том, что вы используете неправильный оператор. |= означает «побитовый или назначить». Другими словами,

  $foo |= $bar;

совпадает с

  $foo = $foo | $bar

В вашем примере происходит то, что ваша новая анонимная хеш-ссылка становится строковой, а затем побитовым ИЛИ со значением $myhash{$key}. Чтобы еще больше запутать ситуацию, если $myhash{$key} не определено в то время, значение представляет собой простую строковую ссылку на хеш-ссылку, которая выглядит как HASH(0x80fc284). Поэтому, если вы проведете краткий осмотр структуры, она может выглядеть как ссылка на хеш, но это не так. Вот несколько полезных выводов через Data::Dumper:

   perl -MData::Dumper -le '$hash{foo} |= { }; print Dumper \%hash'
   $VAR1 = {
             'foo' => 'HASH(0x80fc284)'
           };

А вот что вы получаете, когда используете правильный оператор:

  perl -MData::Dumper -le '$hash{foo} ||= { }; print Dumper \%hash'
  $VAR1 = {
            'foo' => {}
          };
4 голосов
/ 01 октября 2008

Я думаю, что ваша проблема заключалась в использовании "|=" (побитовое или присваивание) вместо "||=" (присваивать, если ложно).

Обратите внимание, что ваш новый код не совсем эквивалентен. Разница в том, что "$myhash{$key} ||= {}" заменит существующие значения, но не ложные, ссылкой на хэш, но новое не будет. На практике это, вероятно, не актуально.

2 голосов
/ 01 октября 2008

Попробуйте это:

my %myhash;
$myhash{$key} ||= {};

Насколько я знаю, вы не можете объявить хеш элемент в предложении my. Сначала вы объявляете хеш, а затем добавляете элемент.

Редактировать: Я вижу, вы вынули my. Как насчет попытки ||= вместо |=? Первый идиоматичен для «ленивой» инициализации.

...