2017-02-15 28 views
12

Сегодня я наткнулся на что-то в Perl, о котором я не знал: он «локализует» переменную, которой присвоены элементы перечисленного списка.Почему Perl не требует, чтобы переменная была объявлена ​​с моим?

Это, конечно же, задокументировано в документации Perl, однако я не смог ее запомнить или прочитать.

Следующий сценарий показывает, что я имею в виду:

use warnings; 
use strict; 

my $g = 99; 

foreach $g (1..5) { 
    p($g); 
} 

sub p { 
    my $l = shift; 
    printf ("%2d %2d\n", $g, $l); 
} 

Скрипт печатает

99 1 
99 2 
99 3 
99 4 
99 5 

потому что $g является "локализован" к петле foreach.

Насколько я могу сказать, что нет никакой разницы, если бы я добавил my к $g в петле Еогеасп:

foreach my $g (1..5) { 

На самом деле, я в конечном итоге делает это, потому что я чувствую, что делает его более ясным, что переменная является локальным для цикла.

Мой вопрос сейчас: есть ли сценарий, в котором мое использование my действительно имеет значение (учитывая, что $g уже объявлен глобально).

+2

Для foreach не требуется мое объявление, если вы его объявили глобально. Странно, однако, что он не будет жаловаться, что вы объявляете это снова. Например, если вы удалите диапазон, он будет жаловаться на то, что вы уже объявили '$ g', я пойду и немного изучу это. –

+0

Если переменная была ранее объявлена ​​с помощью my, она использует эту переменную вместо глобальной, но она все еще локализована в цикле. Эта * неявная локализация происходит только в цикле foreach *. http://perldoc.perl.org/perlsyn.html#Foreach-Loops – user3606329

+0

@ user3606329 Это правильно, но если вы возьмете этот код и удалите диапазон, он создаст ошибку. Переменная еще не находится внутри цикла, она является частью инструкции foreach. –

ответ

8

Исследуемое поведение документировано в Foreach Loops in perlsyn

В foreach цикл перебирает нормальное значение списка и устанавливает скалярную переменную VAR, чтобы быть каждым элементом списка в своей очереди. Если переменной предшествует ключевое слово my, то оно лексически охвачено и, следовательно, видимо только внутри цикла.

, который продолжает объяснения

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

Таким образом, не должно быть никакой разницы между локализацией его my или оставить что foreach.

Немного любопытства является то, что

Этот неявный локализация происходит только в foreach петле.

Все это дальнейшее уточнение в этом фрагменте из Private Variables via my() from perlsub

В foreach по умолчанию петля для определения объема его переменной индекса динамически в виде local.Однако если индексная переменная имеет префикс с ключевым словом my или если в области уже есть лексика, то вместо нее создается новая лексика.

С нового лексического является создается внутри в обоих случаях не может быть никакой практической разницы.

Я абсолютно поддерживаю и рекомендую поставить my.

+0

То есть понятно. Проблема, которую я вижу здесь, заключается в том, что '$ g' еще не находится в цикле. поэтому, если '$ g' не объявлен и ему присвоено значение раньше, то' $ g' на самом деле является пустым значением. –

+0

@Gerry В 'foreach my $ i (1..4) {}' область '$ i' ограничена циклом. Он не существует «раньше». То же самое без 'my', если' $ i' был объявлен ранее - он локализован в области цикла, как только он будет замечен. Это то, что вышеприведенная цитата (ы) сообщают нам. – zdim

+0

ОК, спасибо zdim. В этом есть смысл. –