Принуждение контекста списка в Perl
Я пытаюсь понять контекст Perl, и я споткнулся о камень;
С учетом кода;
#!/usr/bin/perl
my $b = (33,22,11);
print "$b\n";
my $b = () = (33,22,11);
print "$b\n";
my @b = (33,22,11);
print "@b\n";
my @b = () = (33,22,11);
print "@b\n";
Результаты (последняя строка пуста);
11
3
33 22 11
<>
Поскольку второй отпечаток вернул длину списка, я предполагал, что где-то массив был сгенерирован, так как массив в скалярном контексте оценивает его длину. Но четвертый отпечаток, похоже, опровергает это предположение. Я ожидал увидеть " '33 22 11'
но вместо этого ничего не получил. Что здесь происходит?
Ответы
Ответ 1
Вы сбиты с толку, потому что думаете =
- это единственный оператор, в то время как это может привести к двум различным операторам: оператору присваивания списка или скалярному оператору присваивания. Мини-учебник: Scalar vs List Assignment Operator объясняет различия.
my $b = (33,22,11);
------------------ Scalar assign in void context.
---------- List literal in scalar context. Returns last.
my @b = (33,22,11);
------------------ List assign in void context.
---------- List literal in list context. Returns all.
my $b = ( () = (33,22,11) );
--------------------------- Scalar assign in void context.
------------------- List assign in scalar context. Returns count of RHS
---------- List literal in list context. Returns all.
my @b = ( () = (33,22,11) );
--------------------------- List assign in void context.
------------------- List assign in list context. Returns LHS.
---------- List literal in list context. Returns all.
Что касается вашего заголовка, принудительный контекст списка невозможно для каждого. Если функция возвращает список, когда ожидается скаляр, это приводит к дополнительным значениям в стеке, что приводит к тому, что операторы получают неправильные аргументы.
Вы можете, однако, сделать что-то вроде:
( EXPR )[0]
или
( EXPR )[-1]
EXPR
в контексте списка, но целое возвращает только один элемент возвращаемого списка.
Ответ 2
Назначение списка в скалярном контексте возвращает количество элементов в правой части (случай 2). Случай 4 сначала назначает (33, 22, 11)
- ()
, а затем присваивает ()
(значение которого не изменилось) на @b
.
Ответ 3
Отвечая на неявный вопрос в заголовке:
Perl предоставляет встроенный scalar
для принудительного скалярного контекста, когда он иначе не использовался; аналогичного list
builtin не существует, я предполагаю, во многом потому, что это может означать несколько разных вещей, например:
list { code to execute in list context };
может быть определено:
sub list (&) { scalar( () = $_[0]->() ) } # return count of elements
sub list (&) { ( $_[0]->() )[0] } # return first element
sub list (&) { ( $_[0]->() )[-1] } # return last element
sub list (&) { for( $_[0]->() ) {} } # return nothing
Отвечая на вопрос:
Если вы путаете контекст, помните, что операторы накладывают контекст на операнды, а не наоборот. В вашем проблемном случае у вас есть скалярное назначение, присваивание скаляру результата назначения списка, которое ставит назначение списка в скалярном контексте. Чтобы узнать, что происходит, просто посмотрите, что будет присваиваться списку в скалярном контексте. (В общем, операторы возвращают то, что делает наиболее здравым смыслом, а это означает, что правило не запоминается, которое применяется ко всем операторам.)