В чем разница между скалярным и списочным контекстами в 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 преобразует объекты в строку в определенных контекстах. И у каждого нетипизированного языка сценариев, который я использовал, есть подобные понятия.