Есть ли такая вещь, как список в скалярном контексте? - PullRequest
9 голосов
/ 22 ноября 2011
my $mind = ( 'a', 'little', 'confused' );

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

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

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

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

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

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

Ответы [ 6 ]

8 голосов
/ 23 ноября 2011

Литерал списка - это нечто, фактически являющееся списком, записанным в коде, поэтому (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? , которая идетнемного подробнее о списках.

3 голосов
/ 23 ноября 2011

Просто спросите 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" }

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

3 голосов
/ 23 ноября 2011

Я согласен с вами и с perlfaq4. Процитируем perldata, что, вероятно, является исчерпывающей документацией по этому вопросу:

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

(выделено мое).

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

2 голосов
/ 23 ноября 2011

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

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

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

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

my $x = qw(a b c);

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

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

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

2 голосов
/ 23 ноября 2011

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

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