2012-02-16 2 views
12

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

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 
+1

Действительно, нет: если левый список был оценен в скалярном контексте, значение будет 'undef'. Список не является массивом. – darch

+0

@ darch, Это не имеет смысла. '($ hello, $ there, $ world)' (и '(7,8)') не может выполняться в скалярном контексте в '($ hello, $ there, $ world) = (7,8)'. Назначение списка может вернуть 3, если захочет, но нет причин. – ikegami

+0

Я отвечал именно на фразу «тогда [список ($ hello, $ there, $ world)] оценивается в скалярном контексте». Оцените 'my ($ h, $ t, $ w) = (7, 8, undef); скаляр ($ h, $ t, $ w) 'и видеть, что списки не являются массивами. – darch

ответ

14

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

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

Причина это работает, как это так, что вы можете написать что-то вроде этого:

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

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

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

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

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

+0

Ваш ответ имеет смысл, я понимаю, почему он работает таким образом, но меня больше интересует, как это работает. Смотрите мой комментарий на сообщение ikegamis. – Brian

+0

@Brian, в контексте списка вы получаете список левой руки, но в скалярном контексте вы получаете счет правого списка. В обоих случаях это потому, что это самая полезная вещь для возвращения. Дополнительную информацию см. В моем обновленном ответе. – cjm

+0

@Brian, в Perl есть много функций и операторов, которые в скалярном контексте возвращают нечто, отличное от числа элементов, которые они будут возвращать в контексте списка. Вы должны прочитать документы, чтобы узнать, что вернет функция или оператор. – cjm

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

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

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

Я уже создал Mini-Tutorial: Scalar vs List Assignment Operator, который пытается прояснить различия между двумя операторами присваивания и тем, как они ведут себя в скалярном и контекстном контексте.

+0

Я отредактировал это предложение, чтобы немного уточнить: «Мне кажется странным, что этот контекст влияет на часть возвращаемого выражения:« Я знаю, что этот контекст не влияет на оценку и только результат возврата, но я хочу знать как это работает. Если правая часть задания оценивается и затем назначается левой стороне, то почему скаляр получает 2? Правая часть оценивает список 3-х элементов, который затем должен быть назначен скаляру. Это похоже на то, что perl просто решает игнорировать правила приоритета и выбирать, какая часть выражения должна быть возвращена. – Brian

+0

Если, конечно, 'my @greeting = (($ hello, $ there, $ world) = (7,8))' будет давать '@ greeting'' (7,8) 'вместо' ($ hello, $ there, $ world) ', теперь это будет иметь для меня гораздо больше смысла. Но если '@ greeting' получает' ($ hello, $ there, $ world) 'и' $ greeting' получает результат '(7,8)', тогда это не имеет смысла. – Brian

+0

'$ greeting' не получает результат' (7,8) '. На самом деле невозможно получить «$ greeting» результат этого «(7,8)», так как этот «(7,8)» оценивает значение списка, а значение списка не может быть присвоено скаляру. И «@ приветствие», и «$ приветствие» получают результат присвоения списка, который представляет собой либо «список значений, для которых оценивается LHS», либо «количество элементов, на которые оценивается его RHS», в зависимости от контекста. Вы, кажется, подразумеваете, что было бы лучше вернуть что-то другое, не давая никаких оснований, как другие результаты были бы полезны. – ikegami