Подтвердить что ты не робот

Назначение списка в скалярном контексте

Назначение списка в скалярном контексте возвращает количество элементов в правой части:

scalar(my ($hello, $there, $world) = (7,8)); #evaluates to 2

Почему он оценивает правую сторону и производит 2 вместо нового определяемого списка и возвращает 3?

Мне кажется, что $hello получает 7, $there получает 8, а $world получает undef, тогда этот список вычисляется в скалярном контексте, что приведет к 3, так как это число элементов в списке ($hello $there $world). Мне кажется странным, что контекст влияет на часть возвращаемого выражения:

my $greeting = (($hello, $there, $world) = (7,8)); #2

my @greeting = (($hello, $there, $world) = (7,8));
my $greeting_length = @greeting; #3
4b9b3361

Ответ 1

Он задокументировал подсчет элементов справа в perlop (последнее предложение в разделе "Операторы присваивания" ):

Аналогично, назначение списка в контексте списка создает список назначенных lvalues, а назначение списка в скалярном контексте возвращает количество элементов, созданных выражением в правой части присваивания.

Причина, по которой это работает, заключается в том, что вы можете писать такие вещи:

while (my ($key, $value) = each %hash) { ... }

Если подсчитать количество элементов в левой части задания, это будет бесконечный цикл.

Если вы думаете об этом, количество элементов в левой части либо совпадает с правой частью, либо константой (когда вы назначаете список скаляров). В первом случае не имеет значения, какую сторону вы подсчитываете, а во втором случае считать правую сторону более полезной.

С другой стороны, в контексте списка оператор присваивания возвращает левый список, потому что это более полезно. Если вы используете его в контексте, который изменяет элементы списка, вы хотите изменить только что назначенные переменные.

Re: ваш комментарий В вашем примере (7,8) представляет собой двухэлементный список, поэтому оператор присваивания возвращает 2. Когда вы назначаете более короткий список более длинному списку скаляров, правая сторона не "дополняется" с помощью undef до назначения. Вместо этого, любые переменные, которые не имеют значения, связанного с ними из правого списка, составляют reset к их значению по умолчанию. Для скалярной переменной это undef. Для массивов это пустой массив. Для хэшей - пустой хэш.

Ответ 2

Мне кажется странным, что эффект контекста, какая сторона оценивается:

Это не так. Обе стороны (операнды) оператора назначения списка оцениваются, и то, оценивается ли назначение списка в скалярном контексте или контексте списка, никак не влияет на оценку операндов.

Оценивается ли присвоение списка в скалярном контексте или контексте списка, влияет только значение, которое он возвращает.

Ранее я создал Scalar vs List Assignment Operator, который пытается прояснить различия между двумя операторами присваивания и их поведением в скалярном и списочном контексте.

Ответ 3

Почему он оценивает правую часть и выдает 2 вместо вновь определенного списка, который оценивается и возвращает 3?

Потому что это то, что в определении языка сказано, что оно должно делать, потому что это то, что Ларри Уолл решил сделать.

Мне кажется, что $ hello получает 7, $ туда получает 8, а $ world получает undef, тогда этот список оценивается в скалярном контексте

Нет, Perl не работает таким образом. Вы предполагаете, что скалярный контекст - это просто преобразование результата, который был бы получен в контексте списка, в скаляр путем подсчета количества элементов в результате списка, но это просто не правильно... скалярный контекст означает, что операция (в этом случае присваивание) должно давать скалярный результат, и часто есть скалярные результаты, которые более полезны, чем просто число элементов в результате контекста списка, и которые варьируются от оператора к оператору... вы должны проверить документацию за что скаляр производит; это не равномерно. Для назначения списка скалярное значение - это число элементов с правой стороны, потому что это гораздо полезнее, чем число получателей, которое является постоянным. например, if (($a, $b) = $s =~/$re/) верно, если совпадение дало результаты, в отличие от того, чтобы всегда быть истиной, потому что есть два получателя.

Мне кажется странным, что контекст влияет на то, какая часть вычисленного выражения возвращается

В Perl есть куда более странные вещи. Это чувство странности происходит из-за несоответствия между моделями... в этом случае ваше ожидание ортогональности и ваше убеждение, что "скалярный контекст" является оператором в списках, в отличие от прагматического дизайна perl и реальности, что "скалярный контекст" создает контекст который определяет, какой результат произвести. Обратите внимание, что вы можете написать свои собственные функции, которые дают совершенно разные результаты в зависимости от контекста вызова.