The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Разница между "my" и "local" в Perl. (perl structure)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: perl, structure,  (найти похожие документы)
From: Anton Berezin <[email protected]> Newsgroups: fido7.ru.cgi.perl Date: Sun, Dec 05, 1999 at 11:18:15PM +0300 Subject: Разница между "my" и "local" в Perl. Оригинал: http://www.prima.eu.org/tobez/local_my.html > Мож кто вкратце объяснит как всё на самом деле? В чем разница между my > и local, и каковы у них области действия? local ----------------------------- Я не знаю как в действительности *реализованы* local-переменные, но для себя всегда представляю некий стек значений, доступ к головному элементу которого осуществляется по имени переменной, push на который делает команда? оператор? функция? local, а pop происходит неявно, по выходу за пределы блока. Например: #! /usr/bin/perl -w use strict; use vars '$var'; $var = 5; Стек: +---+ $main::var =======> | 5 | +---+ sub s1 { print "$var\n"; } sub s2 { local $var = 37; s1; } s1; Стек внутри s1: +---+ $main::var =======> | 5 | +---+ s2; Стек после local: +----+ $main::var =======> | 37 | +----+ | 5 | +----+ В том числе и внутри s1 вызванного из s2. s1; После возврата из s2 произошёл неявный pop, поэтому: +---+ $main::var =======> | 5 | +---+ То есть локализация переменной это просто удобный способ сохранить старое значение, поработать с переменной, и автоматически старое значение восстановить. Очень часто это используется, например, при закачке файла целиком в скаляр: { local $/; open AA, "< aa" or die $!; $aa = <AA>; close AA; } Вместо гораздо менее изячного: my $slash = $/; $/ = undef; open AA, "< aa" or die $!; $aa = <AA>; close AA; $/ = $slash; Локализовать можно только переменную, занесенную в таблицу символов, и поэтому попытка локализовать my-переменную окончится неудачей: $ perl -e 'my $bla = 6; local $bla = 7;' Can't localize lexical variable $bla at -e line 1. Local в perl5 используется очень редко. Обычно нужно хорошо подумать, прежде чем его употреблять. Практически, кроме приведенного выше примера с $/, мне приходилось применять local только в случае рекурсии, когда одни и те же переменные должны быть видимы из нескольких функций: #! /usr/bin/perl -w use strict; use vars '$depth'; $depth = 0; sub print_current_depth { print "$depth "; } sub foo { local $depth = $depth + 1; foo() if $depth < 10; print_current_depth; } foo; print "\n"; __END__ 10 9 8 7 6 5 4 3 2 1 Использование local оправдано еще в одном случае, а именно, если необходимо создать настоящие вложенные функции. Подробнее об этом - дальше по тексту. my ----------------------------- My - это новинка perl5. My-переменная не попадает в таблицу символов и имеет лексическую область видимости: #! /usr/bin/perl -w use strict; use vars '$var'; # глобальная $var = 'global'; sub s1 { print "$var "; } my $var = 'my-file'; sub s2 { print "$var "; } sub s3 { my $var = 'my-function'; print "$var "; if (1) { my $var = 'my-block'; print "$var "; s2; s1; } print "$var "; s2; s1; } s3; print "\n"; __END__ my-function my-block my-file global my-function my-file global My-переменные просты и понятны, доступ к ним - несколько более быстрый, чем к переменным, входящим в таблицу символов. Единственная область, в которой поведение my-переменных может быть не вполне очевидным, связана с closures (покрытия? закрытия? в общем, closures), а также с `наивными' способами создания вложенных функций a la Pascal. Эта сложность заключается в том, что при задании новой функции, именованной либо анонимной, функция будет иметь доступ ко всем лексическим (my) переменным, которые *существовали во время определения функции*. Если функция определятся несколько раз, как часто бывает с анонимными функциями, то разные `экземпляры' функции будут видеть разные экземпляры лексических переменных: #! /usr/bin/perl -w use strict; my @names = qw(Click Drag Move Push Pop Zapp); sub make_callback { my $name = shift; return sub { print "I am called on $name\n"; } } my %callback = map { $_ => make_callback($_) } @names; for ( sort keys %callback) { print "Action: $_;\t"; $callback{$_}->(); } __END__ Action: Click; I am called on Click Action: Drag; I am called on Drag Action: Move; I am called on Move Action: Pop; I am called on Pop Action: Push; I am called on Push Action: Zapp; I am called on Zapp В этом примере каждая сгенерированная анонимная функция видит свой собственный экземпляр лексической переменной $name, определенной в функции make_callback(). Теперь - пример с неправильной реализацией вложенных функций: #! /usr/bin/perl -w use strict; sub level1 { my $value = shift; sub level2 { print "2: $value; "; } print "1: $value; "; level2(); } level1( 'A'); level1( 'B'); level1( 'C'); print "\n"; __END__ 1: A; 2: A; 1: B; 2: A; 1: C; 2: A; Я надеюсь, читатель уже понял, что происходит в этом случае. Perl не имеет настоящих вложенных функций, и level2() определяется как глобальная функция. Но, по правилам областей видимости, level2() должна иметь доступ к лексической переменной $value. Поскольку my $value создается заново при каждом вызове level1(), а level2() определяется только лишь единожды, level2() будет `видеть' только одну конкретную копию my $value, ту, которая в несколько виртуализованном состоянии (level1 еще ни разу не вызвана!) существовала в момент определения функции level2. До первого вызова level1() эта копия имела неопределённое значение, а после первого вызова стала иметь значение 'A', что мы и видим при прогоне теста. [Замечу в скобках, что эта `виртуализация' наглядно показывает, что my имеет как эффекты времени компиляции, так и эффекты времени выполнения. Впрочем, если подумать, то иначе и быть не может.] В заключение, правильный способ создания вложенных функций в Perl5: #! /usr/bin/perl -w use strict; sub level1 { my $value = shift; local *level2 = sub { print "2: $value; "; }; print "1: $value; "; level2(); } level1( 'A'); level1( 'B'); level1( 'C'); print "\n"; __END__ 1: A; 2: A; 1: B; 2: B; 1: C; 2: C; HTH & cheers, Anton. P.S. Архивная копия этой статьи лежит здесь: http://www.prima.eu.org/tobez/local_my.html

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

 Добавить комментарий
Имя:
E-Mail:
Заголовок:
Текст:




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру