Почему мы не можем инициализировать массивы / хэши состояний в контексте списка? - PullRequest
13 голосов
/ 15 июля 2011

Существует ограничение для массивов и хэшей как переменных состояния. Мы не можем инициализировать их в контексте списка с Perl 5.10:

Итак

state @array = qw(a b c); #Error!

Почему это так? Почему это не разрешено?

Мы можем использовать массивы состояний и инициализировать их таким образом

state @numbers;
push @numbers, 5;
push @numbers, 6;

но почему бы не сделать это напрямую state @numbers = qw(5 6);

Почему Perl не позволяет этого?

Ответы [ 5 ]

15 голосов
/ 15 июля 2011

Согласно perldiag , поддержка инициализации контекста списка запланирована на будущий выпуск:

  • Инициализация переменных состояния в контексте списка в настоящее время запрещена
    (F) В настоящее время реализация «состояния» разрешает только инициализацию скалярных переменных в скалярном контексте.Перепишите state ($a) = 42 как state $a = 42, чтобы перейти от списка к скалярному контексту.Такие конструкции, как state (@a) = foo(), будут поддерживаться в будущем выпуске Perl.

Согласно это сообщение об изменении, сделавшем эту ошибку :

На данный момент запретите инициализацию всех назначений списков переменных состояния, поскольку точная семантика в Perl 6 неясна.Лучше сделать это синтаксической ошибкой, чем иметь одно поведение сейчас, но изменить его позже.[Я считаю, что это консенсус.Если нет, он будет отклонен]

Вместо него вы всегда можете использовать arrayref:

state $arrayRef = [qw(a b c)];

Обратите внимание, что ваш пример

state @numbers;
push @numbers, 5;
push @numbers, 6;

делает не означает то же самое, что state @numbers = qw(5 6) (если бы это работало).Переменная state инициализируется только один раз, но ваш код будет вставлять 5 и 6 в массив каждый раз, когда код был выполнен.

8 голосов
/ 15 июля 2011

Ужасный обходной путь:

state @array;
state $array_is_initialized;
unless ($array_is_initialized) {
    $array_is_initialized = 1;
    @array = (1,2,3);
}
5 голосов
/ 15 июля 2011

Он просто не был написан, потому что это довольно сложно, и заставить его работать для скаляров считалось более важным. Существует опция проверки (Perl_ck_sassign в op.c), которая распознает, когда левая сторона присвоения является операцией padsv, ссылающейся на недавно объявленную переменную state, и переносит ее в специальную операцию once, которая гарантирует что назначение происходит только один раз - но оно даже не пытается распознать назначения списка, вероятно, из-за сложности разбиения конструкции типа (state $a, my $b, state $c) = (1, 2, 3). Забавно, что, похоже, state @a = qw(blah blah blah) было бы достаточно просто, и, очевидно, это менее патологический случай, чем другой вариант назначения списка.

2 голосов
/ 26 ноября 2014

Еще одна работа вокруг:

{
    my @array = qw(1 2 3);
    sub foo {
        print join(", ", @array);
    }
}

foo();

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

Источник

0 голосов
/ 15 июля 2011

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

state @array;
@array = qw( a b c );

Это было бы то же самое, что использовать переменную my, а не state.

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