Когда Perl автоматически инициализирует переменные?

StackOverflow https://stackoverflow.com/questions/260703

  •  06-07-2019
  •  | 
  •  

Вопрос

Вот простой Perl для подсчета количества раз, когда значение встречается в массиве.Это работает без каких-либо предупреждений.

use warnings;
use strict;

my @data = qw(1 1 2 3 4 5 5 5 9);
my %histogram;
foreach (@data)
{
    $histogram{$_}++;
}

Когда тело цикла меняется на

$histogram{$_} = $histogram{$_} + 1;

Perl предупреждает: «Дополнительно используйте неинициализированное значение».

Что происходит под капотом?Почему значение инициализируется, когда оно передается в качестве операнда для оператора ++, и не инициализируется с помощью оператора +?

Это было полезно?

Решение

Оператор + оценивает форму слева и форму справа от нее, а затем возвращает сумму обеих.Оценка хэш-вызова не видит никакого специального контекста.

В оператор ++ встроена особая магия.Цитата из man-страницы Perlop относительно оператора ++:

«undef» всегда рассматривается как числовое значение и, в частности, изменяется на 0 перед приращением (так что пост-инкремент значения undef будет возвращать 0, а не «undef»).

редактировать:Чтобы уточнить разницу, ++ меняет значение на месте, а + просто принимает свои аргументы в качестве входных данных.Когда + видит неопределенное значение, обычно что-то пошло не так, но для ++ ваш пример манипуляции с хешем очень типичен - пользователь хочет обрабатывать undef как 0 вместо того, чтобы каждый раз проверять и инициализировать.Поэтому кажется, что имеет смысл относиться к этим операторам именно так.

Другие советы

Дело не в том, что Perl обязательно инициализирует значения, но не всегда предупреждает о них. Не пытайтесь придумать правило для этого, потому что вы всегда найдете исключения, и как только вы решите, что оно выяснено, следующая версия Perl изменит ваши предупреждения.

В этом случае, как сказал Арлекин, операторы автоинкремента имеют особый случай.

Некоторые операторы намеренно опускают " неинициализированный " предупреждение для вашего удобства потому что они обычно используются в ситуациях, когда 0 или " Значение по умолчанию для левого или единственного операнда имеет смысл.

Это: ++ и - (до или после), + =, - =,. =, | =, ^ =, & amp; =, || =.

Обратите внимание, что некоторые из них ошибочно выдают предупреждение при использовании связанной переменной: см. тесты, помеченные как TODO, в http://perl5.git.perl.org/perl.git/blob/HEAD:/t/op/assignwarn.t .

Как сказал Брайан: он все еще делает это, он просто предупреждает вас. Предупреждения говорят вам об определенных манипуляциях с эффектами, которые вы, возможно, не предполагали.

Вы специально запрашиваете значение $ histogram {$ _} , добавляете 1 к нему и затем назначаете его в тот же слот. Это то же самое, что я не ожидал бы, что здесь будет работать автовивификация:

my $hash_ref = $hash_for{$key_level_1};
$hash_ref->{$key_level_2} = $value;

как здесь:

$hash_for{$key_level_1}{$key_level_2} = $value;

Магия, вероятно, не работает как оптимизация. И оптимизирующий компилятор заметил бы, что a = a + 1 - это то же самое, что и a ++ , так что если бы в языке ассемблера был оператор приращения, он мог бы использовать вместо этого эту оптимизированную инструкцию притворяться, что нужно сохранить первое значение, а затем перезаписать его, потому что оно на самом деле не нужно.

Оптимизация - это дополнительная проверка и издержки один раз для повышения производительности при каждом запуске. Но в динамическом языке нет гарантии, что вы не добавляете накладные расходы с той же скоростью, что в противном случае пытаетесь уменьшить их.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top