Perl позволяет добиваться результата — он гибкий, прощающий и пластичный. Умелые программисты используют его каждый день для любых задач — от однострочников и разовых автоматизаций, до многолетних проектов, выполняемых множеством программистов.
Perl прагматичен. Вы — главный. Вы выбираете, как решать ваши проблемы, и Perl действует в соответствии с вашими намерениями, без фрустраций и церемоний.
Perl будет расти вместе с вами. В течение следующего часа вы узнаете достаточно, чтобы писать реальные полезные программы — и вы поймёте, как работает язык, и почему он работает именно так. Современный Perl применяет это знание и объединённый опыт глобального Perl-сообщества, чтобы помочь вам писать работающий, поддерживаемый код.
Для начала, вы должны понять, как узнать больше.
Perl обладает культурой полезной документации. Утилита perldoc
— часть любой полной инсталляции Perl 5 (footnote: Однако, ваша Unix-подобная система может потребовать установки дополнительного пакета, такого как perl-doc
в Debian или Ubuntu GNU/Linux.). perldoc
отображает документацию для каждого установленного в системе Perl-модуля — будь это базовый модуль или установленный из CPAN (Comprehensive Perl Archive Network, Всеобъемлющая архивная сеть Perl) — а также тысячи страниц обширной встроенной документации Perl.
На сайте http://perldoc.perl.org/ размещены свежие версии документации Perl. Индексы CPAN на http://search.cpan.org/ и http://metacpan.org/ предоставляют документацию по всем модулям CPAN. Другие дистрибутивы Perl 5, такие как ActivePerl и Strawberry Perl, предоставляют локальную документацию в формате HTML.
Используйте perldoc
для чтения документации по модулю или части базовой документации:
$ perldoc List::Util
$ perldoc perltoc
$ perldoc Moose::Manual
Первый пример отображает документацию, встроенную в модуль List::Util
. Второй пример отображает отдельный файл документации, в данном случае — оглавление базовой документации. Третий пример отображает отдельный файл документации, являющийся частью CPAN-дистрибутива (Moose). perldoc
скрывает эти детали; нет никакой разницы между чтением документации по базовой библиотеке, такой как Data::Dumper
, или по установленой из CPAN.
Стандартный шаблон документации включает описание модуля, демонстрацию примеров использования, и затем — детальное разъяснение модуля и его интерфейса. Объём документации различается у разных авторов, но её форма поразительно последовательна.
perldoc perltoc
выводит оглавление базовой документации, а perldoc perlfaq
— оглавление часто задаваемых вопросов (Frequently Asked Questions, FAQ) о Perl 5. perldoc perlop
и perldoc perlsyn
документируют символьные операторы и синтаксические конструкции Perl. perldoc perldiag
объясняет значение предупреждающих сообщений Perl 5. perldoc perlvar
содержит список всех символьных переменных Perl. Ознакомление с этими файлами даст вам отличный общий обзор Perl 5.
Утилита perldoc
имеет много других возможностей (см. perldoc perldoc
). Опция -q
осуществляет поиск указанных ключевых слов по Perl FAQ. Так perldoc -q sort
возвращает три вопроса: How do I sort an array by (anything)? (Как мне отсортировать массив по (чему бы то ни было)?), How do I sort a hash (optionally by value instead of key)? (Как мне отсортировать хеш (опционально по значению вместо ключа)?), и How can I always keep my hash sorted? (Как мне всегда поддерживать мой хеш отсортированным?).
Опция -f
выводит документацию по встроенным функциям Perl. perldoc -f sort
объясняет поведение оператора sort
. Если вы не знаете имени нужной вам функции, просмотрите список доступных встроенных функций в perldoc perlfunc
.
Опция -v
ищет встроенную переменную. Например, perldoc -v $PID
выводит документацию по переменной, содержащей идентификатор процесса текущей программы. В зависимости от вашей оболочки, вам, возможно, придётся соответствующим образом заключить переменную в кавычки.
Опция -l
заставляет perldoc
вывести путь к файлу документации вместо его содержимого (footnote: Имейте ввиду, что модуль может иметь отдельный файл .pod в придачу к файлу .pm).
Опция -m
отображает полное содержимое модуля, код и всё остальное, не выполняя никакого специального форматирования.
Система документации в Perl 5 — POD, или Plain Old Documentation (Старая добрая документация). perldoc perlpod
описывает, как работает POD. В число других инструментов для работы с POD входят podchecker
, который проверяет корректность формы вашей POD-документации, и Pod::Webserver
, отображающий локальную POD-документацию в виде HTML через минимальный веб-сервер.
Изучение Ларри Уоллом (Larry Wall) лингвистики и естественных языков повлияло на дизайн Perl. Язык предоставляет вам потрясающую свободу в решении ваших задач, в зависимости от вашего коллективного стиля, имеющегося времени, ожидаемого срока жизни программы или даже вашего вдохновения. Вы можете писать простой, прямолинейный код, или интегрировать его в большие, чётко структурированные программы. Вы можете выбирать из множества парадигм дизайна, можете избегать или приветствовать использование дополнительных возможностей.
Там, где другие языки навязывают один оптимальный способ написания кода, Perl позволят вам решать, какой вариант более читаемый, или полезный, или весёлый.
У Perl-хакеров есть девиз для этого: TIMTOWTDI, произносится как «Tim Toady» («Тим Тоуди»), или «There's more than one way to do it!» («Есть более чем один способ сделать это!»).
Хотя эта выразительность позволяет мастерам создавать изумительные программы, она же позволяет неблагоразумным и неосторожным устраивать беспорядок. Опыт и хороший вкус приведут вас к написанию хорошего кода. Выбор за вами — но не забывайте о читаемости и поддерживаемости, особенно для тех, кто придёт после вас.
Новички в Perl зачастую могут найти некоторые конструкции трудными для понимания. Многие из этих идиом (Идиомы) предлагают большую (хотя и неочевидную) мощь. Вполне нормально избегать их, пока вы не будете чувствовать себя с ними комфортно.
Изучение Perl подобно изучению нового разговорного языка. Вы изучите несколько слов, составите предложения и вскоре будете наслаждаться простыми беседами. Мастерство приходит с практикой чтения и написания. Вам не обязательно понимать каждую деталь Perl, чтобы быть продуктивным, но принципы, изложенные в этой главе, жизненно важны для вашего роста как программиста.
Ещё одна цель дизайна Perl состоит в том, чтобы пытаться избегать того, что может удивить опытных (Perl) программистов. Например, сложение двух переменных ($first_num + $second_num
) очевидно числовая операция (Числовые операторы); оператор сложения должен воспринимать обе переменные как числовые значения, чтобы получить числовой результат. Независимо от содержимого $first_num
и $second_num
, Perl преобразует их в числовые значения (Числовое приведение типов). Вы выразили своё намерение работать с ними как с числами, использовав числовой оператор. Perl с удовольствием сделает это.
Адепты Perl часто называют этот принцип DWIM, или do what I mean (делай то, что я имею ввиду). Иначе говоря, Perl следует принципу наименьшего удивления. Имея поверхностное понимание Perl (особенно контекста, Контекст), должно быть возможно понять смысл незнакомого выражения. Вы разовьёте этот навык.
Выразительность Perl, кроме того, позволяет новичкам писать полезные программы без необходимости понимать всё. Получающийся код часто называют baby Perl (детский Perl), в том смысле, что почти каждый хочет помочь детям научиться хорошо говорить. Каждый начинает как новичок. Практикуясь и обучаясь у более опытных программистов, вы будете понимать и воспринимать более мощные идиомы и техники.
Например, опытный Perl-хакер может утроить список чисел таким образом:
my @tripled = map { $_ * 3 } @numbers;
…а знаток Perl может написать так:
my @tripled;
for my $num (@numbers)
{
push @tripled, $num * 3;
}
…тогда как новичок попытается сделать следующее:
my @tripled;
for (my $i = 0; $i < scalar @numbers; $i++)
{
$tripled[$i] = $numbers[$i] * 3;
}
Все три подхода делают одно и то же, но каждый использует Perl по-своему.
Опыт в программировании на Perl поможет вам фокусироваться на том, что вам нужно, а не на том, как это сделать. В любом случае, Perl с удовольствием будет выполнять простые программы. Вы можете разрабатывать и усовершенствовать ваши программы для повышения ясности, выразительности, пригодности к повторному использованию и поддерживаемости, частично или целиком. Пользуйтесь преимуществами этой гибкости и прагматизма: намного лучше выполнить вашу задачу эффективно сейчас, чем написать концептуально чистую и красивую программу в следующем году.
В разговорных языка значение слова или фразы может зависеть от того, как вы их используете; локальный контекст помогает прояснить намерение. Например, несоответствующее употребление множественного числа во фразе «Please give me one hamburgers!» (footnote: множественное число существительного не соответствует количеству.) звучит неправильно, так же как неправильный пол в «la gato» (footnote: Артикль женского рода, тогда как существительное — мужского.) заставляет носителей языка посмеиваться. Примите также во внимание местоимение «you» или существительное «sheep», которое может единственным или множественным числом в зависимости от контекста.
Контекст в Perl сходен. Он определяет как количесто, так и вид используемых данных. Perl охотно попытается предоставить именно то, чего вы просите — при условии, если вы это делаете, выбирая соответствующий контекст.
Некоторые операции в Perl ведут себя по-разному в случаях, когда вы хотите получить ноль, один или несколько результатов. Конкретная конструкция в Perl в случае, если вы напишете «Сделай это, но результаты меня не волнуют», может делать нечто совершенно другое по сравнению с «Сделай это, и я ожидаю получить несколько результатов». Другие операции позволяют вам определённо указать, предполагаете ли вы работать с числовыми данными, текстовыми данными, или данными, содержащими «истину» или «ложь».
Контекст может быть коварным если вы пытаетесь писать или читать код на Perl как серию единичных выражений в отрыве от их окружения. Вы можете обнаружить себя хлопающим по лбу после долгой сессии отладки, когда выясните, что ваши предположения относительно контекста были неверны. Если же напротив вы осознаёте контекст, ваш код будет более правильным — а также более чистым, гибким и лаконичным.
Контекст количества определяет, сколько элементов вы ожидаете получить от операции. Близкая параллель — согласование числа между субъектом и глаголом в английском языке. Даже не зная формального определения этого лингвистического принципа, вы, вероятно, поймёте ошибку в предложении «Perl are a fun language». В Perl количество элементов, которое вы запросите, определяет, сколько вы получите.
Предположим, у вас есть функция (Объявление функций) под названием find_chores()
, которая сортирует ваш список домашних дел по приоритету задач. Способ, которым вы вызовете эту функцию, определяет, что она будет делать. У вас можете не быть времени что либо делать, в этом случае вызов функции — это просто попытка выглядеть работящим. У вас может быть достаточно времени для выполнения одной задачи, или, может быть, у вас взрыв энергии в свободный выходной, и вы хотите выполнить как можно больше.
Если вы просто вызовете функция и никак не используете возвращаемое ей значение, вы вызвали функцию в пустом контексте:
find_chores();
Присвоение возвращаемого функцией значения единственному элементу (Скаляры) вычисляет функцию в скалярном контексте:
my $single_result = find_chores();
Присвоение результатов вызова функции массиву (Массивы) или списку, или использование её в списке, вычисляет функцию в списочном контексте:
my @all_results = find_chores();
my ($single_element, @rest) = find_chores();
process_list_of_results( find_chores() );
Скобки во второй строке предыдущего примера группируют объявление двух переменных (Лексическая область видимости), чтобы присвоение вело себя так, как вы ожидаете. Если переменная @rest
не используется, вы можете написать и так:
my ($single_element) = find_chores();
…в этом случае скобки поясняют парсеру Perl 5, что вы подразумеваете списочный контекст для присваивания, несмотря на то, что присваиваете только одному элементу списка. Это неочевидно, но теперь, когда вы знаете об этом, различие контекста количества между этими двумя выражениями должно быть ясно:
my $scalar_context = find_chores();
my ($list_context) = find_chores();
Вычисление функции или выражения — исключая присваивание — в списочном контексте может вызвать путаницу. Списки распространяют списочный контекст на выражения, которые они содержат. Оба этих вызова find_chores()
происходят в списочном контексте:
process_list_of_results( find_chores() );
my %results =
(
cheap_operation => $cheap_results,
expensive_operation => find_chores(), # УПС!
);
Последний пример часто удивляет начинающих программистов, так как инициализация хеша (Хеши) списком значений налагает списочный контекст на find_chores
. Используйте оператор scalar
для наложения скалярного контекста:
my %results =
(
cheap_operation => $cheap_results,
expensive_operation => scalar find_chores(),
);
Почему контекст важен? Зависящая от контекста функция может проверить контекст, в котором она вызывается, и определить, как много работы она должна сделать. В пустом контексте функция find_chores()
может законно ничего не делать. В скалярном контексте она может найти только самую важную задачу. В списочном контексте она должна отсортировать и вернуть весь список.
Другой вид контекста в Perl — контекст значения — определяет, как Perl интерпретирует кусок данных. Вы, вероятно, уже заметили, что Perl проявляет гибкость в определении того, имеете вы число или строку, и преобразовании их в тот вид, в который вы хотите. В обмен на отсутствие обязательств объявлять (или хотя бы следить) какой именно тип данных содержит переменная или выдаёт функция, контекст типа в Perl предоставляет подсказки, которые говорят компилятору, как обращаться с данными.
Perl приводит значения в конкретный надлежащий тип (Приведение типов), в зависимости от используемого вами оператора. Например, оператор eq
проверяет, что строки содержат одну и ту же информацию как строки:
say "Catastrophic crypto fail!" if $alice eq $bob;
Возможно, у вас был ставящий в тупик опыт, когда вы знаете, что строки различаются, но сравнение всё равно показывает, что они одинаковые:
my $alice = 'alice';
say "Catastrophic crypto fail!" if $alice == 'Bob';
Оператор eq
обращается со своими операндами как со строками, принудительно налагая на них строковый контекст. Оператор ==
налагает числовой контекст. В числовом контексте обе строки возвращают 0
(Числовое приведение типов). Убедитесь, что используете соответствующий оператор для того типа контекста, который вам требуется.
Булев контекст имеет место, когды вы используете значение в условном выражении. В предыдущем примере if
вычисляет результат операторов eq
и ==
в булевом контексте.
В редких случаях вам, возможно, понадобится принудительно задать определённый контекст в случае, когда не существует оператора подходящего типа. Чтобы принудительно задать числовой контекст, прибавьте к переменной ноль. Чтобы принудительно задать строковый контекст, конкатенируйте переменную с пустой строкой. Чтобы принудительно задать булев контекст, используйте удвоенный оператор отрицания:
my $numeric_x = 0 + $x; # принудительно задаёт числовой контекст
my $stringy_x = '' . $x; # принудительно задаёт строковый контекст
my $boolean_x = !!$x; # принудительно задаёт булев контекст
Контекст типа проще распознать, чем контекст количества. Как только вы узнаете, какой оператор предоставляет какой контекст (Типы операторов), вы редко будете ошибаться.
Контекст — лишь одна из лингвистических уловок в Perl. Программисты, понимающие эти уловки, могут, бросив взгляд на код, сразу же понять его наиболее важные характеристики. Другая важная лингвистическая особенность — эквивалент местоимений в Perl.
Подразумеваемая переменная-скаляр (ещё называемая переменная-топик), $_
, наиболее примечательна своим отсутствием: многие встроенные операции в Perl работают с содержимым $_
в отсутствие явно указанной переменной. Вы можете использовать $_
и как переменную, но это зачастую излишне.
Многие скалярные операторы Perl (включая chr
, ord
, lc
, length
, reverse
и uc
) работают с подразумеваемой переменной-скаляром, если вы не предоставили альтернативы. Например, встроенная функция chomp
удаляет все завершающие последовательности новых строк из своего операнда (footnote: См. perldoc -f chomp
и $/
для более точных деталей её поведения.):
my $uncle = "Bob\n";
chomp $uncle;
say "'$uncle'";
$_
в Perl имеет ту же самую функцию, что и местоимение it (это) в английском. Без явно указанной переменной, chomp
удаляет все завершающие последовательности новых строк из $_
. Perl понимает, что вы имеете ввиду говоря «chomp
» («обгрызть»); Perl всегда обгрызёт это, так что следующие две строки кода эквивалентны:
chomp $_;
chomp;
Аналогично, say
и print
оперируют с $_
в отстутствие других аргументов:
print; # выводит $_ в текущий дескриптор файла
say; # выводит "$_\n" в текущий дескриптор файла
Средства работы с регулярными выражениями в Perl (Регулярные выражения и сопоставление) по умолчанию используют $_
для сопоставления, замены и транслитерации:
$_ = 'My name is Paquito';
say if /My name is/;
s/Paquito/Paquita/;
tr/A-Z/a-z/;
say;
Директивы циклов в Perl (Директивы циклов) по умолчанию используют $_
как итерационную переменную. Рассмотрим директиву for
, итерирующую по списку:
say "#$_" for 1 .. 10;
for (1 .. 10)
{
say "#$_";
}
…или while
:
while (<STDIN>)
{
chomp;
say scalar reverse;
}
…или map
, преобразовывающую список:
my @squares = map { $_ * $_ } 1 .. 10;
say for @squares;
…или grep
, фильтрующую список:
say 'Brunch time!'
if grep { /pancake mix/ } @pantry;
Как английский становится запутанным, если вы используете слишком много местоимений и антецедентов, так и со смешанным использованием $_
, явным или неявным, нужно быть осторожным. Неосмотрительное параллельное использование $_
может привести к тому, что один кусок кода молча перезапишет значение, записанное другим. Если вы пишете функцию, которая использует $_
, вы можете сломать работу с $_
в вызывающей функции.
Начиная с Perl 5.10 появилась возможность объявлять $_
как лексическую переменную (Лексическая область видимости), чтобы предотвратить такое разрушительное поведение:
while (<STDIN>)
{
chomp;
# ПЛОХОЙ ПРИМЕР
my $munged = calculate_value( $_ );
say "Original: $_";
say "Munged : $munged";
}
Если calculate_value() или любая другая функция изменит $_
, это изменение сохранится на протяжении текущей итерации цикла. Добавление объявления my
предотвращает потерю существующего экземпляра $_
:
while (my $_ = <STDIN>)
{
...
}
Конечно, использование именованной лексической переменной может быть таким же ясным:
while (my $line = <STDIN>)
{
...
}
Используйте $_
, так же, как вы использовали бы слово «это» в формальном письме: экономно, в разумных и хорошо определённых границах.
В Perl 5.12 появился оператор троеточие (...
) как заполнитель для кода, который вы намереваетесь поместить позже. Perl будет парсить его как законченную инструкцию, но выбросит исключение, что вы пытаетесь выполнить неимплементированный код, если вы попытаетесь его запустить. См. подробности в perldoc perlop
.
Perl также предоставляет две неявные переменные-массива. Perl передаёт аргументы в функции (Объявление функций) в массиве @_
. Операции работы с массивами (Массивы) внутри функций по умолчанию воздействуют на эту переменную, поэтому два этих фрагмента кода эквивалентны:
sub foo
{
my $arg = shift;
...
}
sub foo_explicit_args
{
my $arg = shift @_;
...
}
Так же как $_
соответствует местоимению it (это), @_
соответствует местоимениям they (они) и them (их). В отличие от $_
, Perl автоматически локализует для вас @_
когда вы вызываете другие функции. Встроенные функции shift
и pop
работают с @_
, если отсутствуют другие операнды.
Снаружи всех функций подразумеваемая переменная-массив @ARGV
содержит аргументы командной строки, переданные в программу. Операции работы с массивами в Perl (включая shift
и pop
) неявно работают с @ARGV
за пределами функций. Вы не сможете использовать @_
когда подразумеваете @ARGV
.
Оператор <$fh>
в Perl — то же самое, что встроенная функция readline
. readline $fh
делает то же самое, что и <$fh>
. Начиная с Perl 5.10 голая readline
ведёт себя точно так же, как <>
, так что теперь вы можете везде использовать readline
. По историческим причинам <>
— всё ещё более распространённый вариант, однако рассмотрите использование readline
как более читаемой альтернативы. Вы возможно предпочтёте glob '*.html'
варианту <*.html>
, правда? Здесь та же самая идея.
@ARGV
имеет один специальный случай. Если вы читаете из пустого дескриптора файла <>
, Perl будет воспринимать каждый элемент в @ARGV
как имя файла, который нужно открыть для чтения. (Если массив @ARGV
пуст, Perl будет читать со стандартного ввода.) Это неявное поведение @ARGV
полезно при написании коротких программ, таких как этот фильтр для командной строки, изменяющий порядок своих входных данных на противоположный:
while (<>)
{
chomp;
say scalar reverse;
}
Почему scalar
? say
налагает списочный контекст на свои операнды. reverse
передаёт свой контекст своим операндам, обрабатывая их как список в списочном контексте и как конкатенированную строку в скалярном контексте. Если поведение reverse
выглядит сбивающим с толку, ваши инстинкты верны. Perl 5 вероятно должен быть разделить «перевернуть строку» и «перевернуть список».
Если вы запустите этот код со списком файлов:
$ perl reverse_lines.pl encrypted/*.txt
…результат будет одним длинным потоком вывода. Не передавая никаких аргументов, вы можете задать свой собственный стандартный ввод, передав его по конвейеру из другой программы или введя напрямую. Однако, Perl хорош для гораздо большего, чем маленькие программы для командной строки…