Spec-Zone.ru › Perl 5.30

perlsyn

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ОПИСАНИЕ
    • Объявления
    • Комментарии
    • Простые операторы
    • Модификаторы операторов
    • Составные операторы
    • Управление циклами
    • Циклы FOR
    • Циклы FOREACH
    • Основные BLOCKs
    • Операторы выбора
    • GOTO
    • Оператор многоточия
    • POD: Встроенная документация
    • Простые старые комментарии (Не!)
    • Экспериментальные детали по given и when
      • Прерывание
      • Пропускание
      • Возвращаемое значение
      • Переключение в цикле
      • Отличия от Perl 6

НАЗВАНИЕ

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 интерпретировать её как конструктор ссылки на хэш. Считается хорошим стилем использовать эти механизмы различения свободно, не только когда 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: {
    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;
}

Такие конструкции довольно часто используются, как из-за отсутствия официального switch оператора в более старых версиях Perl, так и потому, что новая версия, описанная ниже, остаётся экспериментальной и иногда может быть запутанной.

Операторы 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 для топикалайзера, и вы будете меньше расстроены.

Переход

Хотя не для слабонервных, 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 (это упрощает парсинг), в то время как компилятор фактически знает, как искать escapes 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.30.3/perlsyn

Spec-Zone.ru

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