Что происходит, когда 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