Есть ли такая вещь, как список в скалярном контексте?

my $mind = ( 'a', 'little', 'confused' );

И это потому, что perldoc perlfaq4 объясняет строку выше следующим образом (выделение добавлено):

Поскольку вы назначаете скаляр, правая часть находится в скалярном контексте. Оператор запятой (да, это оператор!) В скалярном контексте оценивает его левую часть, отбрасывает результат, оценивает его правую часть и возвращает результат. По сути, этот список-двойник присваивает $scalar это самая правая ценность. Многие люди путают это, потому что они выбирают список-двойник, последним элементом которого также является ожидаемое количество:

my $scalar = ( 1, 2, 3 );  # $scalar gets 3, accidentally

Я понимаю, что это означает, что в скалярном контексте нет такого понятия, как список.

Тем не менее, ikegami утверждает, что он "приводит [s] к оператору списка, поэтому он является литералом списка".

Так это список или нет?

6 ответов

Решение

Литерал списка - это то, что на самом деле представляет собой список, написанный в коде, поэтому (1, 2, 3) является литералом списка, тогда как caller например, это функция, которая может возвращать список или скаляр в зависимости от контекста.

В строке, как:

my $x = ...;

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

my $x = (1, 2, 3);

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

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

Так что в основном это различие терминологии, с list literal ссылаясь на разделенный запятыми список значений в фактическом исходном коде *, и list ссылаясь на последовательность значений, помещенных в стек perl.

Вы можете написать подпрограммы с возвращаемыми значениями, которые ведут себя как массивы или как списочные литералы в зависимости от контекста.

sub returns_like_array  {my @x = 1..5; return @x}

sub returns_like_list   {my @x = 1..5; return @x[0 .. $#x]}

* или что-то, что приводит к списку значений через запятую, например qw() или толстая запятая => или хеш или фрагмент массива.

Вы также можете посмотреть мой ответ здесь: Как я могу получить первый элемент из функции, которая возвращает массив в Perl? который входит в чуть более подробно о списках.

Я согласен с вами и с perlfaq4, Цитировать perldata, что, вероятно, является окончательной документацией по этому вопросу:

В контексте, не требующем значения списка, значение того, что кажется литералом списка, является просто значением конечного элемента, как в случае с оператором C запятой.

(акцент мой).

Тем не менее, икегами имеет право использовать любую терминологию, которую он хочет. Разные люди думают о разных языковых конструкциях в разных терминах, и, пока конечные результаты одинаковы, я не думаю, что имеет значение, отличается ли их терминология от терминологии в документации. (Однако не стоит настаивать на своеобразной терминологии на публичном форуме!)

Просто спросите Perl!

>perl -MO=Concise,-exec -e"my $s = ($x, $y, $z);"
1  <0> enter
2  <;> nextstate(main 1 -e:1) v:{
3  <0> pushmark v
4  <#> gvsv[*x] s
5  <#> gvsv[*y] s
6  <#> gvsv[*z] s
7  <@> list sKP                      <--- list in (s)calar context.
8  <0> padsv[$s:1,2] sRM*/LVINTRO
9  <2> sassign vKS/2
a  <@> leave[1 ref] vKP/REFC

Так что да, можно иметь список в скалярном контексте.

Невозможно вернуть список в скалярном контексте. (Ну, это возможно из XS, но программа завершится сбоем, возможно, с ошибкой "Bizarre copy".)


Другого не может быть. Если бы существовал отдельный список операций и запятая, было бы невозможно скомпилировать следующее:

sub f { "a", "b", "c" }

Приведет ли это к списку или запятому? На самом деле такого различия нет, так что да, это приводит к тому, что оп.

Это вопрос терминологии и перспективы. Терминология здесь сложная, потому что вы можете написать список в исходном коде, вернуть список значений или оценить что-либо в контексте списка... и слово "список" означает что-то немного различное в каждом случае!

Технически, список не может существовать в скалярном контексте, потому что perl (интерпретатор) не создает список значений для таких вещей:

my $x = ('a', 'b', 'c');

Будучи педантично точным, это объясняется как поведение оператора запятой в скалярном контексте. Так же, qw определяется как возвращение последнего элемента в скалярном контексте, поэтому здесь тоже нет списка:

my $x = qw(a b c);

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

Perl язык абстрактный. На уровне исходного кода ('a', 'b', 'c') это список. Вы можете использовать этот список в выражении, которое налагает на него скалярный контекст, поэтому с этой точки зрения список может существовать в скалярном контексте.

В конце концов, это выбор между ментальными моделями того, как работает [Pp]erl. Модель "Список в скалярном контексте возвращает свое последнее значение" немного неточна, но ее проще понять. Насколько я знаю, нет никаких угловых случаев, когда это функционально некорректно. Модель "Нет такого понятия, как список в скалярном контексте" является более точной, но с ней сложнее работать, так как необходимо учитывать поведение каждого оператора в скалярном контексте.

Это не список. Поскольку вы присваиваете скаляр, это оператор запятой - вычисляет левую сторону, вычисляет правую сторону, возвращает правую сторону и разрешает слева направо. $scalar будет 'confused':)

Другие вопросы по тегам