В чем разница между скалярным и списочным контекстами в Perl?

В чем разница между скалярным и списочным контекстами в Perl, и имеет ли это какую-либо параллель в других языках, таких как Java или Javascript?

3 ответа

Решение

Различные операторы в Perl чувствительны к контексту и дают разные результаты в списке и в скалярном контексте.

Например:

my(@array) = (1, 2, 4, 8, 16);
my($first) = @array;
my(@copy1) = @array;
my @copy2  = @array;
my $count  = @array;

print "array: @array\n";
print "first: $first\n";
print "copy1: @copy1\n";
print "copy2: @copy2\n";
print "count: $count\n";

Выход:

array: 1 2 4 8 16
first: 1
copy1: 1 2 4 8 16
copy2: 1 2 4 8 16
count: 5

Сейчас:

  • $first содержит 1 (первый элемент массива), потому что круглые скобки в my($first) обеспечить контекст массива, но есть только место для одного значения в $first,
  • и то и другое @copy1 а также @copy2 содержать копию @array,
  • а также $count содержит 5, потому что это скалярный контекст, и @array оценивает количество элементов в массиве в скалярном контексте.

Также могут быть построены более сложные примеры (результаты - упражнение для читателя):

my($item1, $item2, @rest) = @array;
my(@copy3, @copy4) = @array, @array;

В других известных мне языках нет прямой параллели со списком и скалярным контекстом.

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

@x = @array;  # copy an array
$x = @array;  # get the number of elements in an array

Другие операторы и функции также являются контекстно-зависимыми:

$x   = 'abc' =~ /(\w+)/;  # $x = 1
($x) = 'abc' =~ /(\w+)/;  # $x = 'abc'
@x   = localtime();       # (seconds, minutes, hours...)
$x   = localtime();       # 'Thu Dec 18 10:02:17 2008'

Как оператор (или функция) ведет себя в данном контексте, зависит от оператора. Не существует общих правил поведения вещей.

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

В дополнение к скалярным и списочным контекстам вы также увидите контексты "void" (ожидаемое возвращаемое значение) и "логическое" (ожидаемое истинное / ложное значение), упомянутые в документации.

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

Я думаю, что лучшее средство понимания контекста - это изучение хотаррей. Итак, представьте, что = это подпрограмма, которая реализует wantarray:

sub = {
  return if ( ! defined wantarray ); # void: just return (doesn't make sense for =)
  return @_ if ( wantarray ); # list: return the array
  return $#_ + 1; # scalar: return the count of the @_
}

Примеры в этом посте работают так, как будто вышеупомянутая подпрограмма вызывается путем передачи правой части в качестве параметра.

Что касается параллелей в других языках, да, я все еще утверждаю, что практически каждый язык поддерживает нечто подобное. Полиморфизм одинаков во всех ОО языках. Другой пример, Java преобразует объекты в строку в определенных контекстах. И у каждого нетипизированного языка сценариев, который я использовал, есть подобные понятия.

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