Какая локализация происходит в цикле «foreach»? - PullRequest
4 голосов
/ 12 февраля 2010

Из perldoc perlsyn по теме циклов Foreach:

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

Но рассмотрим этот пример:

use Devel::Peek;
my $x = 1;
Dump $x;
for $x ( 1 ) { Dump $x }

SV = IV(0x8117990) at 0x8100bd4
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 1
SV = IV(0x8117988) at 0x8100bf8
  REFCNT = 2
  FLAGS = (IOK,READONLY,pIOK)
  IV = 1

Кажется, что это не те же самые переменные.Это ошибка в документах, или я что-то упустил?

Ответы [ 3 ]

5 голосов
/ 12 февраля 2010

Каждое правило нуждается в своем исключении, и оно одно. В цикле for, если переменная цикла является лексической (объявлена ​​с my), Perl создаст новый лексический псевдоним текущего элемента в цикле. Код ОП можно записать следующим образом:

use Data::Alias 'alias';

my $x = 1;
for (2..3) {
    alias my $x = $_;
    # note that $x does not have dynamic scope, and will not be visible in 
    # subs called from within the loop
    # but since $x is a lexical, it can be closed over
}

Редактировать: предыдущий пример был в псевдокоде Perl, ответ исправлен для ясности.

2 голосов
/ 12 февраля 2010

Правильно, его следует называть псевдонимами, чтобы избежать путаницы с local () В CPAN существуют различные модули, которые позволяют использовать псевдонимы и в других обстоятельствах.

0 голосов
/ 12 февраля 2010

Во-первых, поймите, что есть глобальные (пакетные) переменные и есть лексические переменные. Они могут иметь одинаковое имя. Отныне я буду ссылаться на глобальный $ x по его полному имени $::x, что сокращенно означает "глобальный пакет $ x main".

Для обратной совместимости, для циклов используйте локализованные глобальные переменные, если вы не укажете обратное, или $ x уже объявлен лексическим (не осознавал этого). Так for $x (2..3) {} относится к локализованному $ :: x. for my $x (2..3) {} относится к лексическому $ x. В обоих случаях они находятся внутри цикла, например:

for (2..3) {
    my $x = $_;
    ...
}

За исключением того, что $ _ имеет псевдоним $ x, не копируется.

Я полагаю, что вышеизложенное объясняет, почему вы получаете разные скаляры, когда используете Devel :: Peek. Поскольку для лексического эквивалента нет эквивалента local(), он, вероятно, объявляет новый лексический элемент на лексической панели внутри цикла for, как в коде выше.

local($x) также изменяет базовый SV, потому что он делает что-то вроде:

my $original = $x;
my $new;
*::x = \$new;

...

*::x = \$original;

т. создание нового скаляра, подключение его в слот $ x на таблице символов, а затем восстановление старого скаляра, когда закончится область.

Но это действительно только предположение. Вы должны были бы покопаться в коде, чтобы узнать.

Документы, говорящие о том, что лексическое слово «локализовано в цикле», не должны восприниматься как буквальный local(). Термин local сбивает с толку, потому что другие языки, и даже программисты Perl, используют его взаимозаменяемо для обозначения local() и «лексической области действия». local() лучше бы назвать temp(). Так что я думаю, что документы просто немного небрежны с их терминологией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...