perlsyn
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- Объявления
- Комментарии
- Простые операторы
- Модификаторы операторов
- Составные операторы
- Управление циклами
- Циклы For
- Циклы Foreach
- Обработка исключений Try Catch
- Основные BLOCK-ы
- Блоки defer
- Операторы Switch
- Goto
- Оператор Эллипсис
- POD: Встроенная документация
- Простые комментарии (не!)
- Экспериментальные подробности о given и when
НАЗВАНИЕ
perlsyn - Синтаксис Perl
ОПИСАНИЕ
Программа Perl состоит из последовательности объявлений и операторов, выполняемых сверху вниз. Циклы, подпрограммы и другие управляющие структуры позволяют перемещаться внутри кода.
Perl — язык свободной формы: вы можете форматировать и вставлять отступы так, как вам удобно. Пробелы в основном служат для разделения токенов, в отличие от языков, таких как Python, где пробелы являются важной частью синтаксиса, или Fortran, где они не важны.
Многие синтаксические элементы Perl необязательны. Вместо того, чтобы требовать ставить скобки вокруг каждого вызова функции и объявлять каждую переменную, вы часто можете опустить такие явные элементы, и Perl вычислит, что вы имели в виду. Это известно как «сделай, как я хочу», сокращённо DWIM. Это позволяет программистам быть ленивыми и использовать тот стиль кодирования, к которому они привыкли.
Perl заимствует синтаксис и концепции из многих языков: awk, sed, C, Bourne Shell, Smalltalk, Lisp и даже английского языка. Другие языки заимствовали синтаксис из Perl, особенно расширения для регулярных выражений. Поэтому, если вы программировали на другом языке, вы увидите знакомые элементы в Perl. Они часто работают одинаково, но см. perltrap для информации о различиях.
Объявления
Единственное, что вам нужно объявить в Perl, это форматы отчетов и подпрограммы (и иногда даже не подпрограммы). Скалярная переменная содержит неопределённое значение (undef) до тех пор, пока ей не будет присвоено определённое значение, которое является любым значением, кроме undef. При использовании в качестве числа undef обрабатывается как 0; при использовании в качестве строки — как пустая строка, ""; а при использовании в качестве ссылки, которой не присваивается значение, обрабатывается как ошибка. Если вы включите предупреждения, вы получите уведомление об инициализированном значении всякий раз, когда вы будете использовать undef в качестве строки или числа. Ну, обычно. Контексты булевых значений, такие как:
if ($a) {} исключены из предупреждений (потому что им важна истинность, а не определённость). Операторы, такие как ++, --, +=, -=, и .=, которые работают с неопределёнными переменными, такими как:
undef $a;
$a++; также всегда исключаются из таких предупреждений.
Объявление можно поместить в любом месте, где можно разместить оператор, но оно не влияет на выполнение основной последовательности операторов: все объявления действуют на этапе компиляции. Обычно все объявления помещаются в начало или конец скрипта. Однако, если вы используете лексически-ограниченные частные переменные, созданные с помощью my(), state(), или our(), вам нужно убедиться, что ваш формат или определение подпрограммы находится в той же области видимости блока, что и my, если вы хотите иметь доступ к этим частным переменным.
Объявление подпрограммы позволяет использовать имя подпрограммы как оператор списка с этого момента в программе. Вы можете объявить подпрограмму без её определения, сказав sub name, таким образом:
sub myname;
$me = myname $0 or die "can't get myname"; Такое простое объявление объявляет функцию как оператор списка, а не унарный оператор, поэтому нужно быть осторожным при использовании скобок (или or вместо ||). Оператор || связывается слишком жёстко, чтобы его использовать после операторов списка; он становится частью последнего элемента. Вы всегда можете использовать скобки вокруг аргументов операторов списка, чтобы превратить оператор списка обратно в что-то, что ведет себя больше как вызов функции. Кроме того, вы можете использовать прототип ($) для преобразования подпрограммы в унарный оператор:
sub myname ($);
$me = myname $0 || die "can't get myname"; Теперь это разбирается так, как вы ожидаете, но всё же следует привыкнуть к использованию скобок в такой ситуации. Подробнее о прототипах см. perlsub.
Объявления подпрограмм также можно загрузить оператором require или загрузить и импортировать в свой пространство имен с помощью оператора use. Подробнее см. perlmod.
Последовательность операторов может содержать объявления лексически-ограниченных переменных, но помимо объявления имени переменной объявление действует как обычный оператор и обрабатывается в последовательности операторов как обычный оператор. Это означает, что оно действительно оказывает как компиляционное, так и выполнение временное воздействие.
Комментарии
Текст от символа "#" до конца строки является комментарием и игнорируется. Исключением являются "#" внутри строки или регулярного выражения.
Простые операторы
Единственный тип простого оператора — это выражение, вычисляемое для своих побочных эффектов. Каждый простой оператор должен завершаться точкой с запятой, если это не последний оператор в блоке, в этом случае точка с запятой необязательна. Но все же поставьте точку с запятой, если блок занимает более одной строки, потому что вы можете в конечном итоге добавить еще одну строку. Обратите внимание, что есть операторы, такие как eval {}, sub {}, и do {}, которые выглядят как составные операторы, но таковыми не являются — это просто ТЕРМИНЫ в выражении — и, следовательно, им нужно явное завершение при использовании в качестве последнего элемента в операторе.
Модификаторы операторов
Любой простой оператор может быть необязательно последовать за ОДНИМ модификатором, непосредственно перед завершающей точкой с запятой (или окончанием блока). Возможные модификаторы:
if EXPR
unless EXPR
while EXPR
until EXPR
for LIST
foreach LIST
when EXPR За EXPR модификатором следует так называемая «условие». Его истинность или ложность определяет поведение модификатора.
if выполняет оператор один раз, если и только если условие истинно. unless — это противоположное, оно выполняет оператор, если условие ложно (то есть, если условие ложно).
print "Basset hounds got long ears" if length $ear >= 10;
go_outside() and play() unless $is_raining; Модификатор for(each) является итератором: он выполняет оператор один раз для каждого элемента в СПИСКЕ (с $_ как ссылкой на каждый элемент по очереди). В этом формате нет синтаксиса для указания цикла for в стиле C или лексически-ограниченной переменной итерации.
print "Hello $_!\n" for qw(world Dolly nurse); while повторяет оператор, пока условие истинно. Постфикс while имеет такое же магическое обращение с некоторыми типами условий, как и префикс while. until делает обратное, повторяя оператор, пока условие ложно (или пока условие ложно):
# Both of these count from 0 to 10.
print $i++ while $i <= 10;
print $j++ until $j > 10; Модификаторы while и until имеют обычную семантику цикла «while» (условие вычисляется в первую очередь), за исключением случаев, когда они применяются к do-БЛОКУ (или к оператору do-подпрограммы Perl4), в этом случае блок выполняется один раз, прежде чем вычисляется условие.
Это делается для того, чтобы вы могли писать циклы, например:
do {
$line = <STDIN>;
...
} until !defined($line) || $line eq ".\n" См. «do» в perlfunc. Также обратите внимание, что описанные позже операторы управления циклом НЕ будут работать в этой конструкции, так как модификаторы не принимают метки циклов. Извините. Вы всегда можете поместить другой блок внутри него (для next/redo) или вокруг него (для last) для этого.
Для next или redo, просто удвойте фигурные скобки:
do {{
next if $x == $y;
# do something here
}} until $x++ > $z; Для last, вам нужно быть более подробным и поместить фигурные скобки вокруг него:
{
do {
last if $x == $y**2;
# do something here
} while $x++ <= $z;
} Если вам нужны как next, так и last, вам нужно сделать оба и также использовать метку цикла:
LOOP: {
do {{
next if $x == $y;
last LOOP if $x == $y**2;
# do something here
}} until $x++ > $z;
} ПРИМЕЧАНИЕ: Поведение my, state, или our с модификатором оператора, условной конструкцией или циклом (например, my $x if ...) является неопределенным. Значение переменной my может быть undef, любым ранее присвоенным значением или, возможно, любым другим значением. Не полагайтесь на это. Будущие версии Perl могут вести себя иначе, чем версия Perl, которую вы используете. Здесь живут драконы.
Модификатор when — это экспериментальная функция, впервые появившаяся в Perl 5.14. Чтобы использовать её, вам следует включить объявление use v5.14. (Технически, она требует только функции switch, но этот аспект её не был доступен до 5.14.) Оперативная только внутри цикла foreach или блока given, она выполняет оператор только в том случае, если умный матч $_ ~~ EXPR истинен. Если оператор выполняется, за ним следует next изнутри foreach и break изнутри given.
В соответствии с текущей реализацией цикл foreach может находиться где угодно в динамической области видимости модификатора when, но должен находиться в лексической области видимости блока given. Это ограничение может быть снято в будущих выпусках. См. «Операторы Switch» ниже.
Составные операторы
В Perl последовательность операторов, определяющая область видимости, называется блоком. Иногда блок ограничен файлом, содержащим его (в случае требуемого файла или всей программы), а иногда — областью строки (в случае eval).
Но в целом, блок ограничен фигурными скобками, также известными как фигурные скобки. Мы будем называть эту синтаксическую конструкцию BLOCK. Поскольку заключенные фигурные скобки также являются синтаксисом для выражений конструкторов хеш-ссылок (см. perlref), вам иногда может потребоваться снять неоднозначность, поместив ; сразу после открывающей фигурной скобки, чтобы Perl понял, что эта фигурная скобка является началом блока. Вам чаще придется снять неоднозначность другим способом, поместив + непосредственно перед открывающей фигурной скобкой, чтобы заставить её интерпретироваться как выражение конструктора хеш-ссылок. Считается хорошим стилем использовать эти механизмы снятия неоднозначности свободно, не только тогда, когда Perl иначе неправильно предположит.
Следующие составные операторы могут быть использованы для управления потоком:
if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK ...
if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
unless (EXPR) BLOCK
unless (EXPR) BLOCK else BLOCK
unless (EXPR) BLOCK elsif (EXPR) BLOCK ...
unless (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK
given (EXPR) BLOCK
LABEL while (EXPR) BLOCK
LABEL while (EXPR) BLOCK continue BLOCK
LABEL until (EXPR) BLOCK
LABEL until (EXPR) BLOCK continue BLOCK
LABEL for (EXPR; EXPR; EXPR) BLOCK
LABEL for VAR (LIST) BLOCK
LABEL for VAR (LIST) BLOCK continue BLOCK
LABEL foreach (EXPR; EXPR; EXPR) BLOCK
LABEL foreach VAR (LIST) BLOCK
LABEL foreach VAR (LIST) BLOCK continue BLOCK
LABEL BLOCK
LABEL BLOCK continue BLOCK
PHASE BLOCK Начиная с Perl 5.36, вы можете итерировать по нескольким значениям одновременно, указав список лексем в скобках:
no warnings "experimental::for_list";
LABEL for my (VAR, VAR) (LIST) BLOCK
LABEL for my (VAR, VAR) (LIST) BLOCK continue BLOCK
LABEL foreach my (VAR, VAR) (LIST) BLOCK
LABEL foreach my (VAR, VAR) (LIST) BLOCK continue BLOCK Если включена экспериментальная try функция, то также можно использовать следующее
try BLOCK catch (VAR) BLOCK
try BLOCK catch (VAR) BLOCK finally BLOCK Экспериментальный given оператор не включен автоматически; см. "Управляющие операторы switch" ниже, как это сделать, и связанные с этим предостережения.
В отличие от C и Pascal, в Perl все они определены в терминах BLOCK, а не операторов. Это означает, что фигурные скобки обязательны — нет разрешенных «висячих» операторов. Если вы хотите написать условные операторы без фигурных скобок, есть несколько других способов сделать это. Все следующие делают одно и то же:
if (!open(FOO)) { die "Can't open $FOO: $!" }
die "Can't open $FOO: $!" unless open(FOO);
open(FOO) || die "Can't open $FOO: $!";
open(FOO) ? () : die "Can't open $FOO: $!";
# a bit exotic, that last one Оператор if прост. Поскольку BLOCKы всегда ограничены фигурными скобками, никогда не возникает неоднозначности, с каким if оператором else связан. Если вы используете unless вместо if, смысл проверки меняется на обратный. Как и if, unless может быть после else. unless даже может быть после одного или нескольких elsif операторов, хотя, возможно, стоит дважды подумать, прежде чем использовать эту синтаксическую конструкцию, так как каждый, кто читает ваш код, должен будет поразмыслить как минимум дважды, прежде чем понять, что происходит.
Оператор while выполняет блок, пока выражение истинно. Оператор until выполняет блок, пока выражение ложно. Метка необязательна, и если она присутствует, она состоит из идентификатора, за которым следует двоеточие. Метка идентифицирует цикл для управляющих операторов цикла next, last, и redo. Если метка опущена, управляющий оператор цикла относится к самому внутреннему вложенному циклу. Это может включать динамический поиск по вашей стеку вызовов во время выполнения для нахождения метки. Такое отчаянное поведение вызывает предупреждение, если вы используете псевдоним use warnings или флаг -w.
Если выражение условия оператора while основано на любой группе типов итерационных выражений, то оно получает некоторое магическое обращение. Затронутые типы итерационных выражений — readline, оператор ввода <FILEHANDLE>, readdir, glob, оператор подстановки <PATTERN> и each. Если выражение условия является одним из этих выражений, то значение, возвращаемое итерационным оператором, неявно присваивается $_. Если выражение условия является одним из этих выражений или явным присваиванием одного из них скаляру, то условие фактически проверяет определённость значения выражения, а не его обычное истинностное значение.
Если есть continue блок, он всегда выполняется непосредственно перед тем, как условный оператор будет повторно вычислен. Таким образом, его можно использовать для увеличения переменной цикла, даже если цикл был продолжен через оператор next.
Когда блок предваряется ключевым словом компиляции, таким как BEGIN, END, INIT, CHECK или UNITCHECK, тогда блок будет выполняться только во время соответствующей фазы выполнения. Подробнее см. perlmod.
Модули расширений также могут подключаться к парсеру Perl, чтобы определять новые типы составных операторов. Они вводятся ключевым словом, которое распознаёт расширение, а синтаксис, следующий за ключевым словом, определяется исключительно расширением. Если вы разработчик расширения, см. "PL_keyword_plugin" в perlapi для механизма. Если вы используете такой модуль, см. документацию модуля для подробностей о синтаксисе, который он определяет.
Управление циклом
Команда next запускает следующую итерацию цикла:
LINE: while (<STDIN>) {
next LINE if /^#/; # discard comments
...
} Команда last немедленно выходит из соответствующего цикла. Блок continue, если таковой имеется, не выполняется:
LINE: while (<STDIN>) {
last LINE if /^$/; # exit when done with header
...
} Команда redo перезапускает блок цикла, не переоценивая условие. Блок continue, если таковой имеется, не выполняется. Эта команда обычно используется программами, которые хотят солгать самим себе о том, что только что было введено.
Например, при обработке файла, такого как /etc/termcap. Если ваши строки ввода могут заканчиваться обратными слешами для обозначения продолжения, вы хотите перейти к следующему записям.
while (<>) {
chomp;
if (s/\\$//) {
$_ .= <>;
redo unless eof();
}
# now process $_
} что является сокращением Perl для более явно написанного варианта:
LINE: while (defined($line = <ARGV>)) {
chomp($line);
if ($line =~ s/\\$//) {
$line .= <ARGV>;
redo LINE unless eof(); # not eof(ARGV)!
}
# now process $line
} Обратите внимание, что если в приведенном выше коде был блок continue, он бы выполнялся только для строк, отброшенных регулярным выражением (поскольку redo пропускает блок continue). Блок continue часто используется для сброса счётчиков строк или m?pat? однократных совпадений:
# inspired by :1,$g/fred/s//WILMA/
while (<>) {
m?(fred)? && s//WILMA $1 WILMA/;
m?(barney)? && s//BETTY $1 BETTY/;
m?(homer)? && s//MARGE $1 MARGE/;
} continue {
print "$ARGV $.: $_";
close ARGV if eof; # reset $.
reset if eof; # reset ?pat?
} Если слово while заменено словом until, смысл проверки меняется на обратный, но условие все равно проверяется до первой итерации.
Управляющие операторы циклов не работают в if или unless, так как это не циклы. Вы можете удвоить фигурные скобки, чтобы сделать их таковыми.
if (/pattern/) {{
last if /fred/;
next if /barney/; # same effect as "last",
# but doesn't document as well
# do something here
}} Это вызвано тем, что блок сам по себе действует как цикл, который выполняется один раз, см. "Базовые BLOCKы".
Форма while/if BLOCK BLOCK, доступная в Perl 4, больше недоступна. Замените все случаи if BLOCK на if (do BLOCK).
Циклы for
Стиль цикла for Perl по аналогии с соответствующим циклом while; это означает, что следующее:
for ($i = 1; $i < 10; $i++) {
...
} равносильно этому:
$i = 1;
while ($i < 10) {
...
} continue {
$i++;
} Есть одно небольшое отличие: если переменные объявлены с my в разделе инициализации цикла for, область видимости этих переменных точно соответствует циклу for (телу цикла и разделам управления). Для иллюстрации:
my $i = 'samba';
for (my $i = 1; $i <= 4; $i++) {
print "$i\n";
}
print "$i\n"; при выполнении дает:
1
2
3
4
samba В качестве частного случая, если проверка в цикле for (или соответствующем цикле while) пустая, она рассматривается как истинная. То есть, оба
for (;;) {
...
} и
while () {
...
} рассматриваются как бесконечные циклы.
Помимо обычной итерации по индексу массива, for может быть полезен для многих других интересных применений. Вот один, который избегает проблемы, с которой вы сталкиваетесь, если явно проверяете конец файла в интерактивном дескрипторе файла, что заставляет вашу программу зависать.
$on_a_tty = -t STDIN && -t STDOUT;
sub prompt { print "yes? " if $on_a_tty }
for ( prompt(); <STDIN>; prompt() ) {
# do something
} Выражение условия цикла for получает то же магическое обращение, что и readline и т. д., что и выражение условия цикла while.
Циклы foreach
Цикл foreach итерируется по обычному списку значений и устанавливает скалярную переменную VAR для каждого элемента списка по очереди. Если перед переменной стоит ключевое слово my, то она имеет лексическую область видимости, и поэтому она видима только внутри цикла. В противном случае переменная неявно локальна для цикла и восстанавливает своё прежнее значение при выходе из цикла. Если переменная ранее была объявлена с my, она использует эту переменную вместо глобальной, но она все еще локализована в цикле. Эта неявная локализация происходит только для циклов, не похожих на циклы C-стиля.
Ключевое слово foreach является синонимом ключевого слова for, поэтому вы можете использовать любое из них. Если VAR опущено, то $_ получает каждое значение.
Если какой-либо элемент списка LIST является lvalue, вы можете изменить его, изменив VAR внутри цикла. И наоборот, если какой-либо элемент списка LIST не является lvalue, любая попытка изменить этот элемент не удастся. Другими словами, переменная индекса цикла foreach является неявным псевдонимом для каждого элемента в списке, по которому вы выполняете итерацию.
Если какая-либо часть списка LIST является массивом, foreach может сбиться с толку, если вы добавляете или удаляете элементы внутри тела цикла, например, с помощью splice. Поэтому этого делать не следует.
foreach вероятно, не сделает того, что вы ожидаете, если VAR является привязанной или другой специальной переменной. Тоже не следует делать.
Начиная с Perl 5.22, существует экспериментальная разновидность этого цикла, которая принимает переменную, предваряемую обратным слешем для VAR, в этом случае элементы в списке LIST должны быть ссылками. Переменная с обратным слешем станет псевдонимом для каждого элемента, на который ссылается список LIST, который должен быть правильного типа. В этом случае переменная не обязательно должна быть скаляром, и за обратным слешем может следовать my. Чтобы использовать этот формат, вы должны включить refaliasing функцию через use feature. (См. feature. См. также "Присваивание ссылкам" в perlref.)
Начиная с Perl 5.36, вы можете итерироваться по нескольким значениям одновременно. Вы можете итерироваться только с лексическими скалярами в качестве переменных итератора — в отличие от присваивания списков, нельзя использовать undef для обозначения значения, которое не требуется. Это ограничение текущей реализации и может быть изменено в будущем.
Если размер списка LIST не является точным кратным количеству переменных итератора, то на последней итерации «лишние» переменные итератора становятся псевдонимами для undef, как будто к LIST был добавлен , undef столько раз, сколько нужно, чтобы его размер стал точным кратным. Это происходит, независимо от того, является ли LIST литеральным списком или массивом — массивы не расширяются, если их размер не является кратным размеру итерации, в согласии с итерацией массива по одному элементу. Поскольку эти дополнительные элементы не являются lvalue, попытка изменить их не удастся, что соответствует поведению при итерации списка с литеральными undef.
Примеры:
for (@ary) { s/foo/bar/ }
for my $elem (@elements) {
$elem *= 2;
}
for $count (reverse(1..10), "BOOM") {
print $count, "\n";
sleep(1);
}
for (1..15) { print "Merry Christmas\n"; }
foreach $item (split(/:[\\\n:]*/, $ENV{TERMCAP})) {
print "Item: $item\n";
}
use feature "refaliasing";
no warnings "experimental::refaliasing";
foreach \my %hash (@array_of_hash_references) {
# do something with each %hash
}
foreach my ($foo, $bar, $baz) (@list) {
# do something three-at-a-time
}
foreach my ($key, $value) (%hash) {
# iterate over the hash
# The hash is immediately copied to a flat list before the loop
# starts. The list contains copies of keys but aliases of values.
# This is the same behaviour as for $var (%hash) {...}
} Вот как программист C мог бы закодировать определенный алгоритм на Perl:
for (my $i = 0; $i < @ary1; $i++) {
for (my $j = 0; $j < @ary2; $j++) {
if ($ary1[$i] > $ary2[$j]) {
last; # can't go to outer :-(
}
$ary1[$i] += $ary2[$j];
}
# this is where that last takes me
} А вот как программист Perl, более знакомый с языком, мог бы сделать это:
OUTER: for my $wid (@ary1) {
INNER: for my $jet (@ary2) {
next OUTER if $wid > $jet;
$wid += $jet;
}
} Посмотрите, насколько проще это стало? Это чище, безопаснее и быстрее. Это чище, потому что в нём меньше шума. Это безопаснее, потому что, если позже будет добавлен код между внутренними и внешними циклами, новый код не будет случайно выполнен. next явно итерирует другой цикл, а не просто завершает внутренний. И это быстрее, потому что Perl выполняет оператор for быстрее, чем эквивалентный цикл for на C.
Проницательные хакеры Perl могли заметить, что цикл for имеет возвращаемое значение, и это значение можно получить, обернув цикл в блок do. Вознаграждение за это открытие – это предостережение: возвращаемое значение цикла for не определено и может измениться без предупреждения. Не полагайтесь на него.
Обработка исключений Try Catch
Синтаксис try/catch обеспечивает управление потоком, связанное с обработкой исключений. Ключевое слово try вводит блок, который будет выполнен при его обнаружении, а блок catch предоставляет код для обработки любого исключения, которое может быть выброшено первым.
try {
my $x = call_a_function();
$x < 100 or die "Too big";
send_output($x);
}
catch ($e) {
warn "Unable to output a value; $e";
}
print "Finished\n"; Здесь тело блока catch (т.е. оператор warn) будет выполнено, если начальный блок вызывает условный оператор die, или если любая из вызываемых функций выбросит необработанное исключение. Блок catch может проверить лексическую переменную $e в этом случае, чтобы увидеть, что произошло с исключением. Если исключение не было выброшено, то блок catch не выполняется. В любом случае выполнение затем продолжится со следующего оператора — в этом примере с оператором print.
Ключевое слово catch должно быть немедленно после декларации переменной в скобках, которая вводит новую переменную, видимую для тела последующего блока. Внутри блока эта переменная будет содержать значение исключения, которое было выброшено кодом в блоке try. Необязательно использовать ключевое слово my для объявления этой переменной; это подразумевается (как это делается для сигнатур подпрограмм).
Оба блока try и catch могут содержать выражения управления потоком, такие как return, goto, или next/last/redo. Во всех случаях они ведут себя как ожидается, без предупреждений. В частности, выражение return внутри блока try заставит всю содержащую функцию вернуть значение – это в отличие от её поведения внутри блока eval, где оно заставит вернуть только этот блок.
Как и другие синтаксические конструкции управления потоком, try и catch вернут последнее вычисленное значение, если они помещаются в качестве последнего оператора в функции или блоке do. Это позволяет использовать синтаксис для создания значения. В этом случае помните, что нельзя использовать выражение return, так как это вызовет возврат содержащей функции.
my $value = do {
try {
get_thing(@args);
}
catch ($e) {
warn "Unable to get thing - $e";
$DEFAULT_THING;
}
}; Как и другие синтаксические конструкции управления потоком, блоки try не видны для caller() (точно так же, как циклы while или foreach не видны). Последовательные уровни результата caller могут видеть вызовы подпрограмм и блоки eval, поскольку они влияют на работу return. Поскольку блоки try не перехватывают return, они не представляют интереса для caller.
Блоки try и catch могут быть дополнительно последовать третьим блоком, введенным ключевым словом finally. Этот третий блок выполняется после завершения остальной части конструкции.
try {
call_a_function();
}
catch ($e) {
warn "Unable to call; $e";
}
finally {
print "Finished\n";
} Блок finally эквивалентен использованию блока defer и будет вызван в тех же ситуациях; независимо от того, завершится ли блок try успешно, выбросит ли исключение или передаст управление в другое место с помощью return, управления циклом или goto.
В отличие от блоков try и catch, блок finally не разрешается return, goto или использовать любые управляющие циклы. Значение конечного выражения игнорируется и не влияет на возвращаемое значение содержащей функции, даже если оно помещено последним в функции.
Этот синтаксис в настоящее время экспериментальный и должен быть включен с помощью use feature 'try'. Он вызывает предупреждение в категории experimental::try.
Основные BLOCKs
Сам блок (меченый или нет) семантически эквивалентен циклу, который выполняется один раз. Таким образом, вы можете использовать любые операторы управления циклом внутри него, чтобы выйти или перезапустить блок. (Обратите внимание, что это не верно для eval{}, sub{} или, вопреки распространенному мнению, do{} блоков, которые не считаются циклами.) Блок continue является необязательным.
Конструкция блока может быть использована для эмуляции структур case.
SWITCH: {
if (/^abc/) { $abc = 1; last SWITCH; }
if (/^def/) { $def = 1; last SWITCH; }
if (/^xyz/) { $xyz = 1; last SWITCH; }
$nothing = 1;
} Вы также найдёте, что цикл foreach используется для создания топикалайзера и переключателя:
SWITCH:
for ($var) {
if (/^abc/) { $abc = 1; last SWITCH; }
if (/^def/) { $def = 1; last SWITCH; }
if (/^xyz/) { $xyz = 1; last SWITCH; }
$nothing = 1;
} Такие конструкции довольно часто используются, как из-за отсутствия официального оператора switch в более старых версиях Perl, так и из-за того, что новая версия, описанная сразу ниже, остаётся экспериментальной и иногда может быть запутанной.
Блоки defer
Блок, предваряемый модификатором defer, предоставляет раздел кода, который выполняется в более позднее время во время выхода из области видимости.
Блок defer может появиться в любом месте, где разрешен обычный блок или другой оператор. Если поток выполнения достигает этого оператора, тело блока сохраняется на потом, но не вызывается немедленно. Когда поток управления покидает содержащий блок по любой причине, этот сохранённый блок выполняется при выходе. Это обеспечивает возможность отложить выполнение на более позднее время. Это аналогично синтаксису, используемому в некоторых других языках, часто с использованием ключевых слов с именем try / finally.
Этот синтаксис доступен, если включена именованная функция defer, и в настоящее время является экспериментальным. Если включены предупреждения о экспериментальном коде, при его использовании будет выведено предупреждение.
use feature 'defer';
{
say "This happens first";
defer { say "This happens last"; }
say "And this happens inbetween";
} Если несколько блоков defer содержатся в одной области видимости, они выполняются в порядке LIFO; последний достигнутый выполняется первым.
Код, сохранённый блоком defer, будет вызван при выходе из содержащего его блока из-за обычного прохода, явного return, исключений, выброшенных die или распространяемых вызываемыми функциями, goto, или любыми операторами управления циклом next, last или redo.
Если поток выполнения не достигает самого оператора defer, его тело не сохраняется для последующего выполнения. (Это прямо противоположно коду, предоставленному блоком END фазера, который всегда в очереди компилятора независимо от того, достиг ли выполнения оператор, которому он был задан.)
use feature 'defer';
{
defer { say "This will run"; }
return;
defer { say "This will not"; }
} Исключения, выброшенные кодом внутри блока defer, распространяются к вызывающему элементу аналогично любому другому исключению, выброшенному обычным кодом.
Если блок defer выполняется из-за выброшенного исключения и выбросит другое, не определено, что произойдёт, кроме того, что вызывающий элемент обязательно получит исключение.
Помимо выброса исключения, блок defer не может иначе изменить поток управления своего окружающего кода. В частности, он не может заставить содержащую функцию return, а также не может goto метку или управлять содержащим циклом с помощью next, last или redo. Однако эти конструкции разрешены полностью внутри тела defer.
use feature 'defer';
{
defer {
foreach ( 1 .. 5 ) {
last if $_ == 3; # this is permitted
}
}
}
{
foreach ( 6 .. 10 ) {
defer {
last if $_ == 8; # this is not
}
}
} Операторы switch
Начиная с Perl 5.10.1 (ну, 5.10.0, но он не работал правильно), вы можете сказать
use feature "switch"; чтобы включить экспериментальную функцию switch. Это слабо основано на старой версии предложения Raku, но теперь она уже не похожа на конструкцию Raku. Вы также получаете функцию switch, когда объявляете, что ваш код предпочитает работать под версией Perl между 5.10 и 5.34. Например:
use v5.14; В функции "switch" Perl получает экспериментальные ключевые слова given, when, default, continue и break. Начиная с Perl 5.16, можно добавить префикс CORE:: к ключевым словам switch, чтобы получить доступ к функции без оператора use feature. Ключевые слова given и when аналогичны switch и case в других языках — хотя continue не является аналогичным — поэтому код в предыдущем разделе можно переписать как
use v5.10.1;
for ($var) {
when (/^abc/) { $abc = 1 }
when (/^def/) { $def = 1 }
when (/^xyz/) { $xyz = 1 }
default { $nothing = 1 }
} foreach — это способ включения топикалайзера, не связанный с экспериментальными функциями. Если вы хотите использовать высокоэкспериментальный given, то можно записать его так:
use v5.10.1;
given ($var) {
when (/^abc/) { $abc = 1 }
when (/^def/) { $def = 1 }
when (/^xyz/) { $xyz = 1 }
default { $nothing = 1 }
} Начиная с версии 5.14, это также можно записать так:
use v5.14;
for ($var) {
$abc = 1 when /^abc/;
$def = 1 when /^def/;
$xyz = 1 when /^xyz/;
default { $nothing = 1 }
} Или, если вам всё равно, как это делать:
use v5.14;
given ($var) {
$abc = 1 when /^abc/;
$def = 1 when /^def/;
$xyz = 1 when /^xyz/;
default { $nothing = 1 }
} Аргументы к given и when находятся в скалярном контексте, и given присваивает переменной $_ её значение топика.
Точно определить, что делает аргумент EXPR для when, сложно, но в общем случае он пытается угадать, что вы хотите сделать. Иногда он интерпретируется как $_ ~~ EXPR, а иногда нет. Его поведение также отличается, когда он лексически заключён в блок given, чем когда он динамически заключён в цикл foreach. Правила слишком сложны, чтобы быть описанными здесь. См. "Экспериментальные детали по given и when" далее.
Из-за несчастной ошибки в реализации given между Perl 5.10 и 5.16 в этих реализациях версия $_, управляемая given, представляет собой просто лексически скопированную версию оригинальной, а не динамически связанный псевдоним к оригинальной, как это было бы, если бы это был foreach или в спецификации языка Raku, как оригинальной, так и текущей. Эта ошибка была исправлена в Perl 5.18 (и сам лексический $_ был удалён в Perl 5.24).
Если ваш код всё ещё должен работать в более старых версиях, придерживайтесь foreach для вашего топикалайзера, и вы будете менее несчастны.
Переход
Хотя это не для слабонервных, Perl поддерживает оператор goto . Существует три формы: goto-Метка, goto-Выражение и goto-&Имя. Метка цикла фактически не является допустимой целью для goto; это просто имя цикла.
Форма goto-LABEL находит оператор, помеченный меткой LABEL, и возобновляет выполнение оттуда. Её нельзя использовать для перехода в конструкции, требующие инициализации, такие как подпрограммы или цикл foreach. Также она не может использоваться для перехода в оптимизированные конструкции. Она может использоваться для перехода практически в любую другую точку внутри динамической области видимости, включая выход из подпрограмм, но обычно лучше использовать другие конструкции, такие как last или die. Автор Perl никогда не чувствовал необходимости использовать эту форму goto (в Perl, конечно — C — это другой вопрос).
Форма goto-EXPR ожидает имя метки, область видимости которой будет разрешаться динамически. Это позволяет использовать вычисленные goto по типу FORTRAN, но не обязательно рекомендуется, если вы оптимизируете под поддержку:
goto(("FOO", "BAR", "GLARCH")[$i]); Форма goto-&NAME очень магическая и подставляет вызов именованной подпрограммы текущей выполняемой подпрограмме. Это используется подпрограммами AUTOLOAD(), которые хотят загрузить другую подпрограмму и затем симулировать, что другая подпрограмма была вызвана в первую очередь (кроме того, любые изменения в @_ в текущей подпрограмме будут переданы в другую подпрограмму.) После goto, даже caller() не сможет сказать, что эта процедура была вызвана первой.
Практически во всех подобных случаях гораздо лучше использовать механизмы структурированного управления потоком next, last или redo, а не прибегать к goto. Для определённых приложений пара catch и throw из eval{} и die() для обработки исключений также может быть разумным подходом.
Выражение с многоточием
Начиная с Perl 5.12, Perl принимает многоточие "..." в качестве плейсхолдера для кода, который вы ещё не реализовали. Когда Perl 5.12 или более поздняя версия сталкивается с выражением с многоточием, он парсит его без ошибок, но если и когда вы попытаетесь выполнить его, Perl выбросит исключение с текстом Unimplemented.
use v5.12;
sub unimplemented { ... }
eval { unimplemented() };
if ($@ =~ /^Unimplemented at /) {
say "I found an ellipsis!";
} Вы можете использовать выражение с многоточием только для представления полного оператора. Синтаксически "...;" является полным оператором, но, как и в других операторах с точкой с запятой, точка с запятой может быть опущена, если "..." находится непосредственно перед закрывающей фигурной скобкой. Эти примеры показывают, как работает многоточие:
use v5.12;
{ ... }
sub foo { ... }
...;
eval { ... };
sub somemeth {
my $self = shift;
...;
}
$x = do {
my $n;
...;
say "Hurrah!";
$n;
}; Выражение с многоточием не может заменить выражение, являющееся частью более крупного оператора. Эти примеры попыток использовать многоточие являются синтаксическими ошибками:
use v5.12;
print ...;
open(my $fh, ">", "/dev/passwd") or ...;
if ($condition && ... ) { say "Howdy" };
... if $a > $b;
say "Cromulent" if ...;
$flub = 5 + ...; Существуют случаи, когда Perl не может сразу отличить выражение от оператора. Например, синтаксис блока и конструктора анонимной ссылки на хэш одинаковый, если в фигурных скобках нет чего-то, что подсказывает Perl. Многоточие является синтаксической ошибкой, если Perl не предполагает, что { ... } является блоком. Внутри вашего блока вы можете использовать ; перед многоточием, чтобы указать, что { ... } — это блок, а не конструктор ссылки на хэш.
Примечание: Некоторые люди разговорно называют эту часть пунктуации "яда-яда" или "тройная точка", но её истинное название — многоточие.
POD: Встроенная документация
Perl имеет механизм для встраивания документации в исходный код. Если компилятор встречает строку, начинающуюся со знака равенства и слова, как в этом примере:
=head1 Here There Be Pods! Тогда этот текст и весь оставшийся текст до и включая строку, начинающуюся с =cut, будут пропущены. Формат промежуточного текста описан в perlpod.
Это позволяет вам свободно перемежать исходный код и текстовую документацию, например:
=item snazzle($)
The snazzle() function will behave in the most spectacular
form that you can possibly imagine, not even excepting
cybernetic pyrotechnics.
=cut back to the compiler, nuff of this pod stuff!
sub snazzle($) {
my $thingie = shift;
.........
} Обратите внимание, что переводчики pod должны рассматривать только абзацы, начинающиеся с директивы pod (это упрощает парсинг), в то время как компилятор на самом деле знает, что ищет pod-экраны даже внутри абзаца. Это означает, что следующий скрытый текст будет пропущен как компилятором, так и переводчиками.
$a=3;
=secret stuff
warn "Neither POD nor CODE!?"
=cut back
print "got $a\n"; Вероятно, вам не следует полагаться на то, что warn() будет документировано навсегда. Не все переводчики pod ведут себя хорошо в этом отношении, и возможно, компилятор станет более разборчивым.
Также можно использовать директивы pod для быстрого комментирования части кода.
Простые комментарии (не!)
Perl может обрабатывать директивы строк, подобно препроцессору C. С помощью этого можно контролировать представление Perl имен файлов и номеров строк в сообщениях об ошибках или предупреждениях (особенно для строк, обрабатываемых с помощью eval()). Синтаксис этого механизма почти такой же, как у большинства препроцессоров C: он соответствует регулярному выражению
# example: '# line 42 "new_filename.plx"'
/^\# \s*
line \s+ (\d+) \s*
(?:\s("?)([^"]+)\g2)? \s*
$/x при этом $1 — номер строки для следующей строки, а $3 — необязательное имя файла (указанное с или без кавычек). Обратите внимание, что пробелов перед # быть не должно, в отличие от современных препроцессоров C.
В директиве строки есть довольно очевидная ловушка: отладчики и профайлеры будут отображать только последнюю строку исходного кода, которая появляется на определённом номере строки в данном файле. Необходимо быть внимательным, чтобы не создавать конфликты номеров строк в коде, который вы хотите отладить позже.
Вот несколько примеров, которые вы должны сможете набрать в своей командной оболочке:
% perl
# line 200 "bzzzt"
# the '#' on the previous line must be the first char on line
die 'foo';
__END__
foo at bzzzt line 201.
% perl
# line 200 "bzzzt"
eval qq[\n#line 2001 ""\ndie 'foo']; print $@;
__END__
foo at - line 2001.
% perl
eval qq[\n#line 200 "foo bar"\ndie 'foo']; print $@;
__END__
foo at foo bar line 200.
% perl
# line 345 "goop"
eval "\n#line " . __LINE__ . ' "' . __FILE__ ."\"\ndie 'foo'";
print $@;
__END__
foo at goop line 345. Экспериментальные детали по given и when
Как уже упоминалось, функция "switch" считается высокоэкспериментальной; она может меняться без предварительного уведомления. В частности, when имеет сложные поведения, которые, как ожидается, изменятся, чтобы стать менее сложными в будущем. Не полагайтесь на его текущую (неправильную) реализацию. До Perl 5.18 given также имел сложные поведения, о которых вам следует помнить, если ваш код должен работать на более старых версиях Perl.
Вот более длинный пример given:
use feature ":5.10";
given ($foo) {
when (undef) {
say '$foo is undefined';
}
when ("foo") {
say '$foo is the string "foo"';
}
when ([1,3,5,7,9]) {
say '$foo is an odd digit';
continue; # Fall through
}
when ($_ < 100) {
say '$foo is numerically less than 100';
}
when (\&complicated_check) {
say 'a complicated check for $foo is true';
}
default {
die q(I don't know what to do with $foo);
}
} До Perl 5.18 given(EXPR) присваивало значение EXPR лишь лексически охватываемой копии (!) $_, а не динамически охватываемому алиасу, как foreach. Это делало его похожим на
do { my $_ = EXPR; ... } за исключением того, что блок автоматически выходил из него при успешном выполнении when или явном break. Поскольку это была только копия, и она была только лексически, а не динамически охватываемой, с ней нельзя было делать то, что обычно делается в цикле foreach. В частности, это не работало для произвольных вызовов функций, если эти функции могли пытаться получить доступ к $_. Лучше использовать foreach для этого.
Большая часть мощности исходит от неявного smartmatching, который иногда может применяться. Большинство времени, when(EXPR) рассматривается как неявное smartmatch $_, то есть, $_ ~~ EXPR. (См. "Оператор Smartmatch" в perlop для получения дополнительной информации о smartmatching.) Но когда EXPR является одним из 10 исключительных случаев (или похожих вещей), перечисленных ниже, он используется непосредственно как булево значение.
- 1.
-
Вызов пользовательской подпрограммы или вызов метода.
- 2.
-
Совпадение с регулярным выражением в форме
/REGEX/,$foo =~ /REGEX/или$foo =~ EXPR. Также несовпадение с регулярным выражением в форме!/REGEX/,$foo !~ /REGEX/или$foo !~ EXPR. - 3.
-
Smartmatch, использующий явный оператор
~~, напримерEXPR ~~ EXPR.ПРИМЕЧАНИЕ: Часто вам придется использовать
$c ~~ $_, потому что в стандартном случае используется$_ ~~ $c, что часто является противоположным тому, что вы хотите. - 4.
-
Булевы операторы сравнения, такие как
$_ < 10или$x eq "abc". К этим относят шесть числовых сравнений (<,>,<=,>=,==и!=) и шесть строковых сравнений (lt,gt,le,ge,eqиne). - 5.
-
По крайней мере, три встроенные функции
defined(...),exists(...)иeof(...). Возможно, в будущем мы добавим ещё больше функций. - 6.
-
Отрицаемое выражение, будь то
!(EXPR)илиnot(EXPR), или логическое исключающее ИЛИ,(EXPR1) xor (EXPR2). Битовые версии (~и^) не включены. - 7.
-
Оператор проверки файла, за исключением ровно 4 случаев:
-s,-M,-Aи-C, так как они возвращают числовые значения, а не булевы. Оператор проверки файла-zне включен в список исключений. - 8.
-
Операторы переключения
..и.... Обратите внимание, что оператор переключения...совершенно отличается от оператора с многоточием..., описанного выше.
В этих 8 случаях значение EXPR используется непосредственно как булево, поэтому smartmatching не выполняется. Можно сказать, что when — это smartsmartmatch.
Кроме того, Perl проверяет операнды логических операторов, чтобы определить, следует ли использовать smartmatching для каждого из них, применяя к операндам вышеуказанный тест:
- 9.
-
Если EXPR —
EXPR1 && EXPR2илиEXPR1 and EXPR2, тест применяется рекурсивно как к EXPR1, так и к EXPR2. Только если оба операнда также пройдут тест, рекурсивно, выражение будет обработано как булево. В противном случае используется smartmatching. - 10.
-
Если EXPR —
EXPR1 || EXPR2,EXPR1 // EXPR2илиEXPR1 or EXPR2, тест применяется рекурсивно только к EXPR1 (которое само по себе может быть оператором AND более высокой приоритетности, например, и, следовательно, подлежит вышеуказанному правилу), а не к EXPR2. Если EXPR1 должен использовать smartmatching, то EXPR2 также делает это, независимо от того, что содержит EXPR2. Но если EXPR2 не может использовать smartmatching, то второй аргумент тоже не сможет. Это сильно отличается от случая&&, так что будьте внимательны.
Эти правила сложные, но цель состоит в том, чтобы они делали то, что вы хотите (даже если вы не совсем понимаете, почему они это делают). Например:
when (/^\d+$/ && $_ < 75) { ... } будет обработано как булево совпадение, потому что правила говорят, что и совпадение с регулярным выражением, и явная проверка $_ будут обрабатываться как булевы.
Также:
when ([qw(foo bar)] && /baz/) { ... } будет использовать smartmatching, потому что только один из операндов является булевым: другой использует smartmatching, и это побеждает.
Дальше:
when ([qw(foo bar)] || /^baz/) { ... } будет использовать smartmatching (только первый операнд учитывается), тогда как
when (/^baz/ || [qw(foo bar)]) { ... } будет проверять только регулярное выражение, что заставляет рассматривать оба операнда как булевы. Следите за этим, так как массив всегда имеет значение true, что делает его фактически избыточным. Не лучшая идея.
Автологичные булевы операторы всё равно будут оптимизированы. Не стоит писать
when ("foo" or "bar") { ... } Это будет оптимизировано до "foo", поэтому "bar" никогда не будет рассматриваться (даже если правила говорят использовать smartmatch для "foo"). Для такой альтернативы массив ссылок будет работать, так как это запустит smartmatching:
when ([qw(foo bar)] { ... } Это несколько эквивалентно функциональности прохода по умолчанию оператора switch в стиле C (не путать с функциональностью прохода по умолчанию в Perl — см. ниже), где один и тот же блок используется для нескольких case инструкций.
Ещё один полезный сокращенный способ: если вы используете литеральный массив или хеш в качестве аргумента для given, он преобразуется в ссылку. Так что given(@foo) эквивалентно given(\@foo), например.
default ведет себя точно так же, как when(1 == 1), то есть всегда совпадает.
Прерывание
Вы можете использовать ключевое слово break для выхода из окружающего given блока. Каждый when блок неявным образом завершается с помощью break.
Проход по умолчанию
Вы можете использовать ключевое слово continue для прохода по умолчанию от одного случая к следующему непосредственно when или default.
given($foo) {
when (/x/) { say '$foo contains an x'; continue }
when (/y/) { say '$foo contains a y' }
default { say '$foo does not contain a y' }
} Возвращаемое значение
Когда оператор given также является допустимым выражением (например, когда это последняя инструкция блока), он вычисляется как:
-
Пустой список, как только встречается явное
break. -
Значение последнего вычисленного выражения успешного
when/defaultраздела, если он существует. -
Значение последнего вычисленного выражения
givenблока, если ни одно условие не выполняется.
В обоих последних случаях последнее выражение вычисляется в контексте, применённом к given блоку.
Обратите внимание, что в отличие от if и unless, невыполненные when инструкции всегда вычисляются как пустой список.
my $price = do {
given ($item) {
when (["pear", "apple"]) { 1 }
break when "vote"; # My vote cannot be bought
1e10 when /Mona Lisa/;
"unknown";
}
}; В настоящее время given блоки не всегда могут использоваться как полноценные выражения. Это может быть исправлено в будущей версии Perl.
Переключение в цикле
Вместо использования given(), вы можете использовать цикл foreach(). Например, вот один способ подсчитать, сколько раз определённая строка встречается в массиве:
use v5.10.1;
my $count = 0;
for (@array) {
when ("foo") { ++$count }
}
print "\@array contains $count copies of 'foo'\n"; Или в более поздней версии:
use v5.14;
my $count = 0;
for (@array) {
++$count when "foo";
}
print "\@array contains $count copies of 'foo'\n"; В конце всех when блоков присутствует неявный next. Вы можете переопределить его с помощью явного last, если вам нужен только первый совпавший элемент.
Это не работает, если вы явно указываете переменную цикла, как в for $item (@array). Вы должны использовать стандартную переменную $_.
Отличия от Raku
Конструкции smartmatch и given/when в Perl 5 несовместимы с их аналогами в Raku. Самое заметное и наименее важное различие заключается в том, что в Perl 5 скобки необходимы вокруг аргумента для given() и when() (кроме случаев, когда последний используется в качестве модификатора инструкции). Скобки в Raku всегда необязательны в конструкции управления, такой как if(), while(), или when(); их нельзя сделать необязательными в Perl 5 без значительных потенциальных трудностей, потому что Perl 5 будет анализировать выражение
given $foo {
...
} как будто аргумент для given был элементом хеша %foo, интерпретируя фигурные скобки как синтаксис элементов хеша.
Однако существует множество других различий. Например, это работает в Perl 5:
use v5.12;
my @primary = ("red", "blue", "green");
if (@primary ~~ "red") {
say "primary smartmatches red";
}
if ("red" ~~ @primary) {
say "red smartmatches primary";
}
say "that's all, folks!"; Но это совсем не работает в Raku. Вместо этого вы должны использовать оператор (параллелизуемый) any:
if any(@primary) eq "red" {
say "primary smartmatches red";
}
if "red" eq any(@primary) {
say "red smartmatches primary";
} Таблица smartmatch в "Smartmatch Operator" в perlop не идентична той, что предложена спецификацией Raku, в основном из-за различий между моделями данных Raku и Perl 5, а также из-за того, что спецификация Raku изменилась со времени раннего принятия Perl 5.
В Raku when() всегда выполняет неявное smartmatch со своим аргументом, в то время как в Perl 5 это удобно (хотя и потенциально запутанно) подавить это неявное smartmatch в различных довольно слабо определённых ситуациях, как приблизительно описано выше. (Различие в основном заключается в том, что Perl 5 не имеет даже внутренней булевой типа).
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/perlsyn