"my" variable masks earlier declaration in same scope
Это предупреждение на этапе компиляции, которое вы увидите, если по ошибке попытаетесь объявить одну и ту же переменную дважды в одной области видимости.
"my" variable ... masks earlier declaration in same scope at ... line ...
Как это происходит, и как работает переобъявление переменной на каждой итерации цикла?
Если нельзя написать my $x два раза в одной области видимости, то как нам обнулить эту переменную?
Рассмотрим различия между этими двумя случаями:
Простой скрипт
use strict; use warnings; my $x = 'this'; my $z = rand(); my $x = 'that'; print "OK\n";
В этом случае мы получим следующее предупреждение на этапе компиляции:
"my" variable $x masks earlier declaration in same scope at ... line 7. )
Понятно, что это только предупреждение, и при запуске скрипт также выведет "OK".
Блок в условном выражении
use strict; use warnings; my $z = 1; if (1) { my $x = 'this'; my $z = rand(); my $x = 'that'; }
Здесь мы получим следующее предупреждение:
"my" variable $x masks earlier declaration in same scope at ... line 7.
В обоих случаях мы объявили $x дважды в одной области видимости, и в результате будет сгенерировано предупреждение на этапе компиляции.
Во втором примере мы также дважды объявили $z, но от этого никакого предупреждения не появилось. Это потому, что $z в блоке находится в другой области видимости.
Область видимости функции
Тот же код, но в функции:
use strict; use warnings; sub f { my $x = 'this'; my $z = rand(); my $x = 'that'; } f(1); f(2);
Здесь мы тоже получим предупреждение на этапе компиляции (один раз) для переменной $x. Несмотря на то, что переменная $z будет "пробуждаться к жизни" несколько раз, при каждом выхове этой функции. Это в порядке вещей. Переменная $z не вызывает предупреждения: Perl может создавать одну переменную дважды, только нам нельзя этого делать. Во всяком случае, не в пределах одной области видимости.
Область видимости цикла for
Тот же код, но в цикле:
use strict; use warnings; for (1 .. 10) { my $x = 'this'; my $z = rand(); my $x = 'that'; }
Здесь мы тоже получим то же предупреждение один(!) раз для $x, но не для $z.
В этом коде одно и то же происходит каждую итерацию: Perl выделяет память для переменной $z.
Что же в действительности означает "my"?
Смысл my $x в том, что вы говорите perl'у, а именно strict'у, что вы хотите использовать private переменную $x в текущей области видимости. Без этого perl будет искать объявление этой переменной в областях видимости высшего уровня и, если нигде не найдет, то выдаст ошибку этапа компиляции Global symbol requires explicit package name. Каждый блок, каждый вызов функции, каждая итерация цикла - это отдельный мир.
С другой стороны, написав my $x дважды в одной области видимости, вы по сути пытаетесь сказать perl'у два раза одно и то же. В этом нет необходимости, и обычно это значит, что где-то допущена ошибка.
Другими словами, предупреждение, которое мы получаем, относится к компиляции кода, а не к выполнению. Оно относится к объявлению переменной разработчиком, а не к выделению памяти perl'ом во время выполнения.
Как обнулить существующую переменную?
Так если мы не можем написать my $x; дважды в одной области видимости, как нам сделать эту переменную "пустой"?
Прежде всего, если переменная объвлена внутри области видимости, то есть между фигурными скобками, она автоматически исчезнет, когда по ходу выполнения программа покинет эту область видимости.
Если же вам нужно "обнулить" скалярную переменную в текущей области видимости, присвойте ей undef, а если это массив или хэш, чтобы опустошить их, нужно присвоить им пустой список:
$x = undef; @a = (); %h = ();
Итак, внесем ясность. "my" сообщает perl'у, что мы хотим использовать переменную. Когда Perl доходит до кода с таким объявлением переменной, он выделяет память под эту перемунную и ее содержимое. Когда Perl дойдет до кода $x = undef;, @x = (); или undef @x;, он удалит содержимое существующей переменной.
Published on 2013-07-25