Что `$hash{$key} |= {}` делает в Perl?
Я боролся с каким-то Perl, который использует хеш-ссылки.
В итоге оказалось, что моей проблемой была строка:
$myhash{$key} |= {};
То есть "присвойте $myhash{$key} ссылку на пустой хеш, если у него уже нет значения".
Однако разыменование этого и попытка использовать его в качестве хеш-ссылки приводят к ошибкам интерпретатора при использовании строки в качестве хеш-ссылки.
Меняя это на:
if( ! exists $myhash{$key}) {
$myhash{$key} = {};
}
... заставил вещи работать.
Так что у меня нет проблем. Но мне любопытно, что происходит.
Кто-нибудь может объяснить?
4 ответа
Причина, по которой вы видите ошибку использования строки в качестве хеш-ссылки, заключается в том, что вы используете неправильный оператор. |=
означает "побитовый или назначить". Другими словами,
$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' => {}
};
Perl имеет сокращенные операторы присваивания. ||=
Оператор часто используется для установки значений по умолчанию для переменных из-за возможности Perl иметь логические операторы, возвращающие последнее оцененное значение. Проблема в том, что вы использовали |=
который побитовый или вместо ||=
что логично или.
Начиная с Perl 5.10 лучше использовать //=
вместо. //
является логически определенным оператором "или" и не терпит неудачу в угловом случае, где определено текущее значение, но false.
Я думаю, что ваша проблема использовала |=
"(побитовое или присваивание) вместо" ||=
"(присвойте, если false).
Обратите внимание, что ваш новый код не совсем эквивалентен. Разница в том, что $myhash{$key} ||= {}
"заменит существующие-но-ложные значения хеш-ссылкой, а новое - нет. На практике это, вероятно, не имеет значения.
Попробуй это:
my %myhash;
$myhash{$key} ||= {};
Вы не можете объявить хеш- элемент в my
пункт, насколько я знаю. Сначала вы объявляете хеш, а затем добавляете элемент в.
Редактировать: я вижу, вы вынули my
, Как насчет попытки ||=
вместо |=
? Первое идиоматично для "ленивой" инициализации.