Spec-Zone.ru › Perl 5.34

perlsyn

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ОПИСАНИЕ
    • Объявления
    • Комментарии
    • Простые операторы
    • Модификаторы операторов
    • Составные операторы
    • Управление циклами
    • Циклы For
    • Циклы Foreach
    • Обработка исключений Try Catch
    • Основные BLOCKы
    • Операторы Switch
    • Goto
    • Оператор Эллипсиса
    • POD: Встроенная документация
    • Простые старые комментарии (не так!)
    • Экспериментальные детали по given и when
      • Выход из цикла
      • Проход насквозь
      • Возвращаемое значение
      • Переключение в цикле
      • Отличия от Raku

НАЗВАНИЕ

perlsyn - Синтаксис Perl

ОПИСАНИЕ

Программа Perl состоит из последовательности объявлений и операторов, которые выполняются сверху вниз. Циклы, подпрограммы и другие управляющие структуры позволяют перемещаться по коду.

Perl — язык свободной формы: вы можете форматировать и отступать его как вам угодно. Пробелы в основном служат для разделения токенов, в отличие от языков, таких как Python, где они являются важной частью синтаксиса, или Fortran, где они не имеют значения.

Многие синтаксические элементы Perl являются необязательными. Вместо того, чтобы требовать от вас ставить скобки вокруг каждого вызова функции и объявлять каждую переменную, вы часто можете опустить такие явные элементы, и Perl выведет то, что вы имели в виду. Это известно как Do What I Mean, сокращенно 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.

END_OF_DOCUMENT_MARKER

В текущей реализации цикл 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

Если включена экспериментальная функция try, также можно использовать следующие:

try BLOCK catch (VAR) 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
}}

Это вызвано тем, что сам блок работает как цикл, который выполняется один раз, см. "Основные BLOCKs".

Форма 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 (телу цикла и разделам управления). Чтобы проиллюстрировать:

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, она используется вместо глобальной, но всё ещё ограничена циклом. Эта неявная локализация происходит только в цикле 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 в стиле 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.

Этот синтаксис в настоящее время экспериментальный и должен быть включен с помощью use feature 'try'. Он генерирует предупреждение в категории experimental::try.

Основные BLOCKs

Блок сам по себе (именованный или нет) семантически эквивалентен циклу, который выполняется один раз. Таким образом, вы можете использовать любые операторы управления циклом в нём для выхода или перезапуска блока. (Обратите внимание, что это НЕ верно в eval{}, sub{}, или, вопреки распространённому мнению, в блоках do{}, которые НЕ считаются циклами.) Блок continue необязателен.

Конструкции BLOCK можно использовать для эмуляции структур switch.

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. Это слабо основано на старой версии предложения Raku, но больше не напоминает конструкцию Raku. Вы также получаете функцию 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 или в спецификации языка Raku. Эта ошибка была исправлена в Perl 5.18 (и лексическая форма $_ сама была удалена в Perl 5.24).

Если ваш код всё ещё должен работать в более старых версиях, используйте foreach для вашего топикализатора, и вам будет меньше грустно.

Goto

Хотя это не для слабонервных, Perl поддерживает оператор goto . Есть три формы: goto-Метка, goto-Выражение и goto-&Имя. Метка цикла фактически не является допустимой целью для goto; это просто имя цикла.

Форма goto-Метка находит оператор, помеченный меткой Метка, и возобновляет выполнение оттуда. Нельзя использовать её для перехода в любую конструкцию, требующую инициализации, такую как подпрограмма или цикл 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 не предполагает, что { ... } является блоком. Внутри вашего блока вы можете использовать ; перед эллипсисом, чтобы указать, что { ... } является блоком, а не конструктором ссылки на хэш.

Примечание: Некоторые люди разговорно называют эту часть пунктуации «яда-яда» или «тройная точка», но ее истинное название — эллипсис.

Документация, встроенная в код

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;
    .........
}

Обратите внимание, что переводчики под должны рассматривать только абзацы, начинающиеся с директивы под (это упрощает парсинг), в то время как компилятор на самом деле знает, как искать под-экраны даже посреди абзаца. Это означает, что следующая скрытая информация будет проигнорирована как компилятором, так и переводчиками.

$a=3;
=secret stuff
 warn "Neither POD nor CODE!?"
=cut back
print "got $a\n";

Вероятно, вам не следует полагаться на то, что warn() будет всегда подготавливаться. Не все переводчики под ведут себя хорошо в этом отношении, и, возможно, компилятор станет более избирательным.

Также можно использовать директивы под, чтобы быстро прокомментировать часть кода.

Простые комментарии (не!)

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.

Оператор проверки файла, за исключением четырёх: -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 (не путать с функциональностью «fallthrough» в 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.

END_OF_DOCUMENT_MARKER

Обратите внимание, что в отличие от 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 smartmatch и 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";
}

Таблица smartmatch в "Оператор smartmatch" в perlop не идентична предложенной спецификацией Raku, в основном из-за различий между моделями данных Raku и Perl 5, а также из-за того, что спецификация Raku изменилась, поскольку Perl 5 ускоренно перешёл к раннему внедрению.

В Raku when() всегда выполнит неявное smartmatch со своим аргументом, в то время как в Perl 5 удобно (хотя и потенциально запутанно) подавлять это неявное smartmatch в различных довольно слабо определённых ситуациях, как примерно описано выше. (Разница в основном потому, что в Perl 5 нет даже внутреннего типа boolean.)

© 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.34.0/perlsyn

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API