2015-11-18 2 views
9

Мой тест выглядит следующим образом:Может кто-нибудь объяснить, почему Perl ведет себя таким образом (переменная область охвата)?

use strict; 
use warnings; 

func(); 
my $string = 'string'; 
func(); 

sub func { 
    print $string, "\n"; 
} 

И результат:

Use of uninitialized value $string in print at test.pl line 10. 

string 

Perl позволяет вызывать функцию до того, как было определено. Однако, когда функция использует переменную, объявленную только после вызова функции, переменная представляется неопределенной. Это где-то документировано? Спасибо!

+3

* Always * 'use strict; использовать предупреждения; '! – Biffen

+0

О, я на самом деле имею эти прагмы в своем тестовом файле. Я отредактирую его. Спасибо. – darkgrin

ответ

12

Поведение my документировано в perlsub - это сводится к этому - perl знает $string находится в области видимости - потому что my говорит это так.

МОЯ оператор объявляет перечисленные переменные, которые будут лексический ограничен блоком ограждающего, условная (если/если/ELSIF/другое), петли (для/Еогеаспа /, а/до/продолжить), подпрограмма, Eval, или do/require/use'd.

Это означает, что он «находится в области видимости» от точки, в которой он «виден» до закрывающей скобки текущего «блока». (Или в вашем примере - конец кода)

Однако - в вашем примере myтакже присваивает значение.

Этот процесс определения области видимости происходит во время компиляции - где perl проверяет, где это действительно для использования $string или нет. (Спасибо strict). Однако - он не может знать, что такое значение, потому что это может измениться во время выполнения кода. (И нетривиальна для анализа)

Так что, если вы это сделаете, это может быть немного понятнее, что происходит:

#!/usr/bin/env perl 
use strict; 
use warnings; 

my $string; #undefined 
func(); 
$string = 'string'; 
func(); 

sub func { 
    print $string, "\n"; 
} 

$string находится в области видимости, в обоих случаях - потому что my произошло во время компиляции - перед вызовом подпрограммы - но оно не имеет значения, установленного за пределами значения по умолчанию undef перед первым вызовом.

Примечание это контрастирует с:

#!/usr/bin/env perl 
use strict; 
use warnings; 

sub func { 
    print $string, "\n"; 
} 

my $string; #undefined 
func(); 
$string = 'string'; 
func(); 

Какие ошибки, потому что, когда к югу объявляется, $string не в области.

4

Прежде всего, я бы рассмотрел это неопределенное поведение, так как он пропускает выполнение my, как my $x if $cond;.

Таким образом, поведение в настоящее время является последовательным и предсказуемым. И в этом случае он ведет точно, как и ожидалось, если оптимизация, которая гарантировала уведомление о неопределенном поведении, не выходила.


Во время компиляции, my имеет эффект объявления и выделение переменной [1]. Скаляры инициализируются undef при создании. Массивы и хеши создаются пустым.

my $string был обнаружен компилятором, поэтому переменная была создана. Но поскольку вы еще не выполнили задание, оно по-прежнему имеет значение по умолчанию (undefined) во время первого вызова func.

Эта модель позволяет захватывать переменные затворами.

Пример 1:

{ 
    my $x = "abc"; 
    sub foo { $x } # Named subs capture at compile-time. 
} 

say foo(); # abc, even though $x fell out of scope before foo was called. 

Пример 2:

sub make_closure { 
    my ($x) = @_; 
    return sub { $x }; # Anon subs capture at run-time. 
} 

my $foo = make_closure("foo"); 
my $bar = make_closure("bar"); 

say $foo->(); # foo 
say $bar->(); # bar 

  1. Распределение, возможно, отложить до тех пор переменная фактически не используется.
+0

Я не следую. Запуск 'perl -MDevel :: Peek -e'mysub(); мой $ foo; sub mysub {Dump ($ foo)} ''показывает' $ foo' с флагом PADMY, а 'perl -MDevel :: Peek -e'mysub(); sub mysub {Dump ($ foo)} ''(очевидно) нет. Я не знаю много о perlguts, поэтому я мог бы быть в стороне, но похоже, что «мой» не пропускается. Не могли бы вы объяснить больше? – ThisSuitIsBlackNot

+0

@ThisSuitIsBlackNot, Неопределенное поведение, чтобы использовать лексическую varaible перед ИСПОЛЬЗОВАНИЕМ 'my', который его объявляет *. Его ИСПОЛНЕНИЕ появилось после первого вызова функции func() 'в коде OP. Поэтому его программа основана на неопределенном поведении. Вы просто показали, что «мой» имеет эффект компиляции, как я уже сказал. (* Это не слова, используемые документами. Это мое понимание нечетких документов). – ikegami