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 — обратное, он выполняет оператор если условие ложно (то есть, если условие ложно). См. "Скалярные значения" в perldata для определений истинности и ложности.
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-блоку (или к Perl4-оператору do-подпрограммы), в этом случае блок выполняется один раз перед оценкой условия.
Это позволяет писать циклы, такие как:
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 интерпретировать её как конструктор ссылки на хэш. Считается хорошим стилем использовать эти механизмы различения свободно, не только когда 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 — левостороннее выражение, вы можете его изменить, изменив VAR внутри цикла. В обратном случае, если какой-либо элемент LIST — НЕ левостороннее выражение, любая попытка изменить этот элемент потерпит неудачу. Другими словами, переменная индекса цикла 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 в стиле C.
Проницательные программисты Perl, возможно, заметили, что цикл for имеет возвращаемое значение и что это значение можно получить, обернув цикл в блок do. Вознаграждение за это открытие — это следующее предостережение: возвращаемое значение цикла for не определено и может измениться без предварительного уведомления. Не полагайтесь на него.
Основные блоки
БЛОК сам по себе (метящийся или нет) семантически эквивалентен циклу, который выполняется один раз. Таким образом, вы можете использовать любые операторы управления циклом в нём, чтобы выйти из него или перезапустить. (Обратите внимание, что это НЕ верно в eval{}, sub{}, или вопреки распространённому мнению do{} блоках, которые НЕ считаются циклами.) Блок continue является необязательным.
Конструкцию БЛОК можно использовать для эмуляции структур switch.
SWITCH: {
if (/^abc/) { $abc = 1; last SWITCH; }
if (/^def/) { $def = 1; last SWITCH; }
if (/^xyz/) { $xyz = 1; last SWITCH; }
$nothing = 1;
} Вы также обнаружите, что foreach цикл использовался для создания topicalizer и switch:
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, так и потому, что новая версия, описанная непосредственно ниже, остаётся экспериментальной и иногда может быть запутанной.
Операторы switch
Начиная с Perl 5.10.1 (ну, 5.10.0, но он не работал правильно), вы можете сказать
use feature "switch"; чтобы включить экспериментальную функцию switch. Она основана на старой версии предложения для Raku, но больше не похожа на конструкцию Raku. Вы также получаете функцию switch всякий раз, когда объявляете, что ваш код предпочитает работать под версией Perl 5.10 или более поздней. Например:
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 — это способ задать topicalizer без экспериментальных возможностей. Если вы хотите использовать сильно экспериментальную 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 присваивает переменной $_ её значение topic.
Точно описать, что делает аргумент EXPR для when, трудно, но в общем случае он пытается угадать, что вы хотите сделать. Иногда он интерпретируется как $_ ~~ EXPR, а иногда — нет. Он также ведёт себя по-разному, когда лексически заключён в блок given, чем когда динамически заключён в цикл foreach. Правила слишком сложны для описания здесь. Смотрите "Экспериментальные подробности о given и when" позже.
Из-за неудачной ошибки в реализации given между Perl 5.10 и 5.16 в этих реализациях версия $_, управляемая given, представляет собой всего лишь лексически область видимости копию оригинала, а не динамически область видимости псевдоним оригинала, как это было бы, если бы это было foreach или в соответствии как с оригинальной, так и с текущей спецификацией языка Raku. Эта ошибка была исправлена в Perl 5.18 (а сама лексически $_ была удалена в Perl 5.24).
Если ваш код всё ещё должен работать в более старых версиях, придерживайтесь foreach для вашего topicalizer, и вам будет меньше проблем.
Переход
Хотя не для слабонервных, 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, чтобы быстро закомментировать раздел кода.
Простые комментарии (Не!)
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 (который сам может быть оператором AND более высокой приоритетности, например, и, следовательно, подпадает под предыдущее правило), а не к 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 для перехода от одного случая к следующему непосредственно 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
Конструкции умного соответствия Perl 5 и given/when несовместимы с их аналогами в 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";
} Таблица умных соответствий в "Оператор умного соответствия" в perlop не идентична той, что предложена в спецификации Raku, в основном из-за различий между моделями данных Raku и Perl 5, но также и потому, что спецификация Raku изменилась с момента раннего принятия Perl 5.
В Raku 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.32.0/perlsyn