perlsyn
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
НАЗВАНИЕ
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) — итератор: он выполняет оператор один раз для каждого элемента в СПИСКЕ (с $_, проходящим по каждому элементу).
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. Это ограничение может быть ослаблено в будущей версии. См. «Операторы выбора» ниже.
Составные операторы
В 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 Экспериментальный given оператор не включён автоматически; см. "Операторы выбора" ниже, как это сделать, и связанные с этим замечания.
В отличие от 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 в стиле C Perl работает так же, как соответствующий цикл while; это означает, что следующее:
for ($i = 1; $i < 10; $i++) {
...
} эквивалентно следующему:
$i = 1;
while ($i < 10) {
...
} continue {
$i++;
} Есть одно небольшое различие: если переменные объявлены с my в разделе инициализации цикла for, область видимости этих переменных точно соответствует циклу for (телу цикла и секциям управления).
В качестве специального случая, если проверка в цикле 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, она используется вместо глобальной, но всё ещё локальна для цикла. Эта неявная локализация происходит только в цикле foreach.
Ключевое слово 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.)
Примеры:
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 which each %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 выполняет оператор foreach быстрее, чем эквивалентный цикл for.
Проницательные программисты Perl могли заметить, что цикл for имеет возвращаемое значение, и это значение можно захватить, обернув цикл в блок do. Награда за это открытие – это предостерегающий совет: Возвращаемое значение цикла for не определено и может меняться без предварительного уведомления. Не полагайтесь на него.
Основные BLOCKы
БЛОК сам по себе (меченый или нет) семантически эквивалентен циклу, который выполняется один раз. Таким образом, вы можете использовать любые операторы управления циклом в нём, чтобы выйти из него или перезапустить его. (Обратите внимание, что это НЕ верно в 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:
SWITCH:
for ($var) {
if (/^abc/) { $abc = 1; last SWITCH; }
if (/^def/) { $def = 1; last SWITCH; }
if (/^xyz/) { $xyz = 1; last SWITCH; }
$nothing = 1;
} Подобные конструкции довольно часто используются, как из-за того, что в более старых версиях Perl не было официального switch оператора, так и потому, что новая версия, описанная непосредственно ниже, остаётся экспериментальной и иногда может быть запутанной.
Операторы Switch
Начиная с Perl 5.10.1 (хорошо, 5.10.0, но он не работал правильно), вы можете сказать
use feature "switch"; чтобы включить экспериментальную функцию switch. Она основана на старой версии предложения Perl 6, но больше не похожа на конструкцию Perl 6. Вы также получаете функцию switch всякий раз, когда объявляете, что ваш код предпочитает работать под версией Perl 5.10 или более поздней. Например:
use v5.14; В рамках функции "switch" Perl получает экспериментальные ключевые слова given, when, default, continue, и break. Начиная с Perl 5.16, можно префикс ключевых слов switch с CORE:: для доступа к функции без оператора 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 или согласно спецификации Perl 6, как изначальной, так и текущей. Эта ошибка была исправлена в Perl 5.18 (и лексически ограниченный $_ был удалён в Perl 5.24).
Если ваш код всё ещё должен работать в старых версиях, придерживайтесь foreach для вашего топикалайзера, и вам будет меньше печально.
Goto
Хотя и не для слабонервных, Perl поддерживает оператор goto. Существует три формы: goto-Метка, goto-Выражение и goto-&Имя. Метка цикла фактически не является допустимой целью для goto; это просто имя цикла.
Форма goto-Метка находит оператор, помеченный меткой LABEL, и возобновляет выполнение оттуда. Она не может использоваться для перехода в любой конструкцию, требующую инициализации, такую как подпрограмма или цикл foreach. Она также не может использоваться для перехода в конструкцию, которая оптимизирована. Она может использоваться для перехода практически в любое другое место в динамическом пространстве имен, включая выход из подпрограмм, но обычно лучше использовать другие конструкции, такие как last или die. Автор Perl никогда не чувствовал необходимости использовать эту форму goto (в Perl, разумеется — C — это другой вопрос).
Форма goto-Выражение ожидает имя метки, область видимости которой будет разрешена динамически. Это позволяет вычислять goto аналогично FORTRAN, но не рекомендуется, если вы оптимизируете под поддерживаемость:
goto(("FOO", "BAR", "GLARCH")[$i]); Форма goto-&Имя очень магична и подставляет вызов именованной подпрограммы вместо текущей выполняемой подпрограммы. Это используется подпрограммами 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 для этого.
Большая часть мощности исходит от неявного интеллектуального сопоставления, которое может иногда применяться. Большую часть времени when(EXPR) обрабатывается как неявное интеллектуальное сопоставление $_, то есть $_ ~~ EXPR. (См. "Оператор интеллектуального сопоставления" в perlop для получения дополнительной информации об интеллектуальном сопоставлении.) Но когда EXPR относится к одному из 10 исключительных случаев (или к подобным им вещам), перечисленным ниже, он используется непосредственно как булево значение.
- 1.
-
Вызов пользовательской подпрограммы или вызов метода.
- 2.
-
Сопоставление с регулярным выражением в форме
/REGEX/,$foo =~ /REGEX/, или$foo =~ EXPR. Также отрицательное сопоставление с регулярным выражением в форме!/REGEX/,$foo !~ /REGEX/, или$foo !~ EXPR. - 3.
-
Интеллектуальное сопоставление, использующее явный оператор
~~, такой как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 используется непосредственно как булево, поэтому интеллектуальное сопоставление не выполняется. Можно представить when как умноженное интеллектуальное сопоставление.
Кроме того, Perl проверяет операнды логических операторов, чтобы решить, использовать ли интеллектуальное сопоставление для каждого из них, применяя вышеуказанный тест к операндам:
- 9.
-
Если EXPR является
EXPR1 && EXPR2илиEXPR1 and EXPR2, тест применяется рекурсивно к обоим EXPR1 и EXPR2. Только если оба операнда также проходят тест, рекурсивно, выражение будет рассматриваться как булево. В противном случае используется интеллектуальное сопоставление. - 10.
-
Если EXPR является
EXPR1 || EXPR2,EXPR1 // EXPR2, илиEXPR1 or EXPR2, тест применяется рекурсивно только к EXPR1 (что само по себе может быть оператором И с более высоким приоритетом, например, и, таким образом, подлежит предыдущему правилу), а не к EXPR2. Если EXPR1 должен использовать интеллектуальное сопоставление, то EXPR2 также делает это, независимо от того, что содержит EXPR2. Но если EXPR2 не может использовать интеллектуальное сопоставление, то и второй аргумент тоже не будет. Это сильно отличается от случая&&, так что будьте осторожны.
Эти правила сложные, но цель в том, чтобы они делали то, что вы хотите (даже если вы не совсем понимаете, почему они это делают). Например:
when (/^\d+$/ && $_ < 75) { ... } будет рассматриваться как булево совпадение, потому что правила указывают, что и сопоставление с регулярным выражением, и явная проверка $_ будут рассматриваться как булевы.
Также:
when ([qw(foo bar)] && /baz/) { ... } будет использовать интеллектуальное сопоставление, потому что только один из операндов является булевым: другой использует интеллектуальное сопоставление, и это побеждает.
Далее:
when ([qw(foo bar)] || /^baz/) { ... } будет использовать интеллектуальное сопоставление (только первый операнд рассматривается), тогда как
when (/^baz/ || [qw(foo bar)]) { ... } будет проверять только регулярное выражение, что заставляет оба операнда рассматриваться как булевы. Следите за этим, потому что массив ссылок всегда имеет истинное значение, что делает его фактически избыточным. Не лучшая идея.
Автологичные булевы операторы по-прежнему будут оптимизироваться. Не стоит писать
when ("foo" or "bar") { ... } Это будет оптимизировано до "foo", поэтому "bar" никогда не будет рассматриваться (хотя правила указывают на использование интеллектуального сопоставления с "foo"). Для такого альтернативного случая массив ссылок будет работать, так как это вызовет интеллектуальное сопоставление:
when ([qw(foo bar)] { ... } Это несколько эквивалентно функциональности пропусков в операторе switch в стиле C (не путать с функцией пропусков в Perl — см. ниже), где один и тот же блок используется для нескольких case инструкций.
Другой полезный ярлык состоит в том, что если вы используете литеральный массив или хеш в качестве аргумента к given, он преобразуется в ссылку. Так, например, given(@foo) эквивалентно given(\@foo).
default ведет себя точно так же, как when(1 == 1), то есть всегда соответствует.
Выход
Вы можете использовать ключевое слово break для выхода из окружающего given блока. Каждый when блок неявно завершается с помощью break.
Пропуск
Вы можете использовать ключевое слово continue для пропуска от одного case к следующему непосредственно следующему 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). Вы должны использовать стандартную переменную $_.
Отличия от Perl 6
Конструкции Perl 5 интеллектуального сопоставления и given/when несовместимы со своими аналогами в Perl 6. Наиболее заметное и наименее важное отличие заключается в том, что в Perl 5 круглые скобки требуются вокруг аргумента к given() и when() (за исключением случаев, когда последний используется как модификатор оператора). Круглые скобки в Perl 6 всегда необязательны в операторе управления, таком как 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!"; Но это совсем не работает в Perl 6. Вместо этого вы должны использовать оператор (параллелизуемый) any:
if any(@primary) eq "red" {
say "primary smartmatches red";
}
if "red" eq any(@primary) {
say "red smartmatches primary";
} Таблица интеллектуальных сопоставлений в "Оператор интеллектуального сопоставления" в perlop не идентична той, что предложена спецификацией Perl 6, в основном из-за различий между моделями данных Perl 6 и Perl 5, а также потому, что спецификация Perl 6 изменилась с момента спешки Perl 5 в раннее принятие.
В Perl 6 when() всегда выполнит неявное интеллектуальное сопоставление со своим аргументом, в то время как в Perl 5 удобно (хотя потенциально путано) подавить это неявное интеллектуальное сопоставление в различных, довольно слабо определенных ситуациях, примерно как описано выше. (Различие в основном связано с тем, что Perl 5 не имеет, даже внутри, булевого типа.)
© 1993–2020 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.28.3/perlsyn