замыкания в perl и регулярные выражения - PullRequest
4 голосов
/ 27 января 2011

Я обнаружил возможную ошибку в замыканиях perl и $1 переменных регулярного выражения. Просто они не смешиваются вместе.

Давайте возьмем этот код.

use warnings;

while ("1234567890"=~/(.)/sg) {
    push @subs, sub{print $1;};
}

for (@subs) {$_->()}

Вы могли бы представить, что Perl теперь будет печатать все числа - вместо этого я получил 10 предупреждений от undefined $1.

Это действительно ошибка, или я просто что-то пропустил в документации по Perl? Есть ли какая-то причина, почему $1 должно быть неопределенным и НЕ быть частью замыкания?

Ответы [ 2 ]

8 голосов
/ 27 января 2011

Perl имеет две отдельные, но в значительной степени совместимые переменные системы.Глобальные переменные, которые находятся в таблице символов, и лексические переменные, которые находятся в лексических площадках, связанных с областью видимости.

Глобальные переменные могут быть целью символической разыменования и могут подвергаться динамической области видимости с local.Лексические переменные (определенные с помощью my) могут быть закрыты.

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

Чтобы это исправить, просто скопируйте значение в лексический:

use warnings;

while ("1234567890"=~/(.)/sg) {
    my $x = $1;                # creates a new lexical that the sub closes over
    push @subs, sub{print $x;};
}

for (@subs) {$_->()}
7 голосов
/ 27 января 2011

Я думаю, что ответ похож на ответ на закрытие perl и $ _ .$1 также является глобальной переменной.

Что вам нужно сделать, это:

my $x = $1;
push @subs, sub{print $x;};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...