Скалярный и список контекста в Perl
1 @backwards = reverse qw(yabba dabba doo);
2 $backwards = reverse qw(yabba dabba doo);
3
4 print @backwards; #gives doodabbayabba
5 print $backwards."\n"; #gives oodabbadabbay
6 print @backwards."\n"; #gives 3
В приведенном выше коде почему line 6
дать 3 в качестве выхода? Почему он конвертируется в скалярный контекст, если он соединен с \n?
Спасибо
3 ответа
Ваш вопрос в конечном итоге "почему @backwards находится в скалярном контексте в строке 6", и возникает вопрос: "Как я могу определить контекст термина?".
Контекст определяется термином "что вокруг" (то есть его "контекст").
Как я могу определить контекст термина? Посмотрев на оператора / функцию, которая использует термин.
Какие шаги вы могли бы предпринять, чтобы самостоятельно выяснить контекст для @backwards, если у вас не было полезных ребят из stackru, чтобы рассказать вам о его контексте?
Здесь мы имеем
print @backwards."\n"
так что есть два оператора / функции. Как мы узнаем, какой из них предоставляет контекст для @backwards? Консультируясь с приоритетом. В верхней части perlop.pod у нас есть таблица приоритетов Perl (print - это "оператор списка"):
left terms and list operators (leftward)
...
left + - .
...
nonassoc list operators (rightward)
О, отлично, теперь нам нужно знать, идет ли печать влево или вправо. Изучив раздел "Термины и операторы списка (влево)" в perlop (сразу после списка приоритетов), мы видим, что print находится здесь справа, потому что мы не заключили его аргументы в скобки.
Таким образом, конкатенация имеет более высокий приоритет, поэтому конкатенация предоставляет контекст для @backwards.
Следующим шагом является проверка документов (снова perlop) для объединения:
Binary "." concatenates two strings.
Строки являются скалярами, поэтому двоичные "." объединяет два скаляра.
И у нас наконец есть это!
@backwards имеет скалярный контекст, потому что конкатенация предоставляет скалярный контекст каждому из его операндов.
Woo. Это было легко, не так ли:-)
Строка 6 дает 3, потому что .
оператор накладывает скалярный контекст как на свои операнды, так и на @backwards
в скалярном контексте дает 3 (потому что любой массив в скалярном контексте сообщает о количестве элементов в нем).
Пытаться:
print "@backwards\n";
Чтобы объединить элементы в массиве, используйте join
:
print join(', ', @backwards) . "\n";
Контекст хитрый. И иногда пара пикселей может иметь все значение. Рассмотрим следующие две строки:
print localtime, "\n";
print localtime. "\n";
Вы заметили разницу?
Эти два утверждения выглядят действительно похожими. Но то, что происходит в двух случаях, очень разное.
В первом утверждении print передается список аргументов. И документация для печати говорит, что она навязывает контекст списка своим аргументам. Поэтому вызов localtime оценивается в контексте списка, и функция возвращает список чисел.
Во втором утверждении print получает единственный аргумент. Этот аргумент является строкой, созданной путем объединения результатов вызова localtime с символом перевода строки. Оператор конкатенации накладывает скалярный контекст на оба своих операнда. Поэтому вызов localtime возвращает текущее время в удобочитаемом формате строки. Затем эта строка объединяется с новой строкой, и полученная строка передается на печать. Вызов print все еще оценивает свой аргумент в контексте списка, но этот контекст не имеет значения для способа интерпретации однострочного аргумента.
Для другого, похожего, посмотрите на более странные углы контекста в Perl, посмотрите вопрос, который я разместил в своем блоге пару дней назад. Я опубликую решение через несколько дней.