суббота, 29 ноября 2014 г.

Печать массива в Perl.

Многое в языке Perl кажется новичку странным, неожиданным, необъяснимым. При внимательном рассмотрении так оно и оказывается. Попробуем произвести весьма простую операцию: распечатаем массив. Получим:

1 my @words = qw(awesome cats hunter);
2 print @words;      # -> "awesomecatshunter"
3 print "@words";    # -> "awesome cats hunter"
4 print "" . "@words";  # -> "awesome cats hunter"
5 print "" . @words;    # -> 3

Отчего же так происходит? На первый взгляд вывод должен быть одинаковым, как независимо от наличия кавычек произошло бы со скалярами:

1 $word = "supersonic";
2 print $word;
3 print "$word";
4 print "" . "$word";
5 print "" . $word;    # -> все будет "supersonic" без перевода каретки

Как обычно для Perl, вступают в действие темные силы контекстов. В первом варианте мы имеет дело со списочным контекстом. Т.е. просто передаем список аргументов функции print и она их печатает, разделяя строкой, содержащейся в магической переменной $, . Кроме того, переменная $\ печатается в конце списка. По умолчанию обе эти переменные не определены, что равносильно значению "" в строковом контексте. Так что print не только не переводит каретку, но и лепит содержащиеся в списке строки вплотную без пробелов. Впрочем, оба этих поведения лишь непривычны, например, питонисту, но весьма правильны и удобны для обрабоки текста. Попробуем теперь поменять значения магических переменных:

1 $, = "--";
2 $\ = "END\n";
3 print @words;      # -> "awesome--cats--hunterEND" с возвратом каретки

Пойдем дальше. Если мы помещаем идентификатор массива в строку с двойными кавычками (см. 3я и 4я строки первого листинга заметки), вступает в дело контекст строковой интерполяции. В этом контексте массив интерполируется в строку с разделителем $" по умолчанию равному " " (пробел). Эту фичу можно красиво использовать для отладочного отображения аргументов функции. Аргументы могут содержать пробелы, и для ясности сепаратор можно локально поменять:

 1 sub is_fatherof {
 2   if ($debug) {
 3     local $" = "][";
 4     print "args = [@_]\n";
 5   }
 6   conquer_the_universe...;
 7 }
 8 
 9 $debug = 1;
10 is_fatherof('Darth Vader', 'Luke Skywalker'); # -> "args = [Darth Vader][Luke Skywalker]"

Вобщем, строковая интерполяция массива эквивалентна join $", @words

Последний пример (print "" . @words) демонстрирует поведение массива в скалярном контексте. Да, в этом контексте массив заменяется своей длиной. Perl is SATAAAN!!! Спасибо за внимание.