Что происходит, когда my() является условным?
Сравните с помощью perl -w -Mstrict
:
# case Alpha
print $c;
...
# case Bravo
if (0) {
my $c = 1;
}
print $c;
...
# case Charlie
my $c = 1 if 0;
print $c;
Alpha
и Bravo
оба жалуются на глобальный символ, не имеющий явного имени пакета, чего и следовало ожидать. Но Charlie
не дает такого же предупреждения, только то, что значение неинициализировано, что сильно пахнет:
# case Delta
my $c;
print $c;
Что именно происходит под капотом? (Даже если что-то вроде этого никогда не должно быть написано для производственного кода)
Ответы
Ответ 1
Вы можете думать о объявлении my
как о действии во время компиляции и во время выполнения. Во время компиляции объявление my
сообщает компилятору, чтобы он заметил, что символ существует и будет доступен до конца текущей лексической области. Назначение или другое использование символа в этом объявлении будет выполняться во время выполнения.
Итак, ваш пример
my $c = 1 if 0;
похож на
my $c; # compile-time declaration, initialized to undef
$c = 1 if 0; # runtime -- as written has no effect
Обратите внимание, что это различие времени компиляции/времени выполнения позволяет вам писать такой код.
my $DEBUG; # lexical scope variable declared at compile-time
BEGIN {
$DEBUG = $ENV{MY_DEBUG}; # statement executed at compile-time
};
Теперь вы можете догадаться, что такое выход этой программы?
my $c = 3;
BEGIN {
print "\$c is $c\n";
$c = 4;
}
print "\$c is $c\n";
Ответ 2
ответ mob - отличное объяснение того, что в настоящее время происходит (и почему), но не забывайте, что perldoc perlsyn
сообщает нам:
ПРИМЕЧАНИЕ.. Поведение a my
, state
или our
, измененное условной или контурной конструкцией оператора (например, my $x
if ...
), undefined. Значение переменной my
может быть undef
, любое ранее присвоенное значение или, возможно, что-либо еще. Не полагайтесь на это. Будущие версии perl могут делать что-то другое из версии perl вы попробуете ее. Здесь будут драконы.
Не рассчитывайте на этот результат или объяснение того, что он по-прежнему остается верным в будущих версиях Perl. (Хотя это, вероятно, будет.)
Ответ 3
Конструкция "my $foo = val if cond" и ее поведение undefined меня много раз укусило за эти годы. Я хочу, чтобы компилятор мог просто отказаться от него (зачем хранить что-то на языке с undefined поведением?!), но, по-видимому, это невозможно сделать для обратной совместимости или по другим причинам. Лучшее решение, которое я нашел, это предотвратить его с помощью perlcritic:
http://search.cpan.org/perldoc?Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations