Область видимости переменных в Perl

my scope

В Perl существует два основных типа переменных. Один из них - это глобальные переменные модуля, объявленные либо с помощью ныне устаревшей конструкции use vars, либо с помощью our.

Другой тип - это лексические переменные, объявленные с помощью my.

Давайте посмотрим, что происходит, когда мы объявляем переменную с помощью my. В каких местах кода переменная будет доступна? Другими словами, где будет область видимости переменной?

Область видимости: содержащий блок

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

{
    my $email = 'foo@bar.com';
    print "$email\n";     # foo@bar.com
}
# print $email;
# $email не существует
# Global symbol "$email" requires explicit package name at ...

Внутри безымянного блока (пара фигурных скобок {}) мы видим объявление новой переменной "$email". Эта переменная существует на участке между ее объявлением и концом блока. Вот почему строка после закрывающей скобки } закомментирована. Если убрать # из строки # print $email; и попробовать запустить скрипт, мы получим ошибку компиляции: Global symbol "$email" requires explicit package name at ....

Другими словами, область видимости переменной, объявленной с помощью my ограничивается содержащим ее блоком.

Область видимости: видимый везде

Переменная $lname объявлена в начале кода. Она будет видима везде до конца файла. Даже внутри блоков. Даже если эти блоки являются объвлениями функций. Если мы изменим переменную внутри блока, ее значение изменится и в остальном коде. Даже если вы выйдете из блока:

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

my $lname = "Bar";
print "$lname\n";        # Bar

{
    print "$lname\n";    # Bar
    $lname = "Other";
    print "$lname\n";    # Other
}
print "$lname\n";        # Other

Переменная, скрытая другим объявлением

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

my $fname = "Foo";
print "$fname\n";        # Foo

{
    print "$fname\n";    # Foo

    my $fname  = "Other";
    print "$fname\n";    # Other
}
print "$fname\n";        # Foo

В этом случае переменная $fname объвлена в начале кода. Как сказано выше, она будет видима везде до конца файла, за исключением мест, где она будет "скрыта" локально объявленной переменной с таким же именем.

Внутри блока мы объявли с помощью my другую переменную с таким же именем. По сути, это скроет переменную $fname, объявленную снаружи блока, пока мы не покинем блок. В конце блока (}) переменная $fname, объявленная внутри него, будет уничтожена, а первоначальная $fname снова станет доступна. Эта особенность особенно важна, так как она дает возможность создавать переменные внутри небольших блоков, не задумываясь о возможном использовании такого же имени снаружи блока.

Одинаковые имена в разных блоках

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

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

{
    my $name  = "Foo";
    print "$name\n";    # Foo
}
{
    my $name  = "Other";
    print "$name\n";    # Other
}

объявление в модуле внутри файла

Это немного более продвинутый пример, и, возможно, здесь стоит обратить внимание:

Perl позволяет переключаться между пространствами имен внутри одного файла с помощью ключевого слова package. Объявление модуля с помощью package НЕ создает область видимости. Если вы объявите переменную, явно указав пространство имен с помощью package main, которое и по умолчанию является телом вашего скрипта, то ваша переменная $fname все равно будет видима в этом файле, даже в других пространствах имен.

Если вы объявите переменную "$lname" в пространстве имен "Other", она будет видима, если потом вы переключитесь обратно на пространство имен main. Если же объявление package Other было в другом файле, то переменные, объявленные там, будут находиться в другой области видимости, созданной файлом.

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

my $fname  = "Foo";
print "$fname\n";    # Foo

package Other;
use strict;
use warnings;

print "$fname\n";    # Foo
my $lname = 'Bar';
print "$lname\n";    # Bar


package main;

print "$fname\n";    # Foo
print "$lname\n";    # Bar

Otras páginas

Учебник Perl по-русски
'my' variable masks earlier declaration in same scope
'my' variable masks earlier declaration in same scope

Author

Gabor Szabo (szabgab) Gabor Szabo