Spec-Zone.ru › Perl 5.38

perlsyn

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ОПИСАНИЕ
    • Объявления
    • Комментарии
    • Простые операторы
    • Модификаторы операторов
    • Составные операторы
    • Управление циклами
    • Циклы For
    • Циклы Foreach
    • Обработка исключений Try Catch
    • Основные BLOCKы
    • Блоки defer
    • Операторы 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

Значение, идущее после модификатора, называется «условием». Его истинность или ложность определяет, как будет вести себя модификатор.

if выполняет оператор один раз, если и только если условие истинно. unless — противоположное, оно выполняет оператор, если условие ложно (то есть, если условие ложно).

print "Basset hounds got long ears" if length $ear >= 10;
go_outside() and play() unless $is_raining;

Модификатор for(each) — это итератор: он выполняет оператор один раз для каждого элемента в СПИСКЕ (с $_, присвоенным каждому элементу по очереди). Нет синтаксиса для указания цикла for в стиле C или лексически-ограниченной переменной итерации в этом формате.

print "Hello $_!\n" for qw(world Dolly nurse);

while повторяет оператор, пока условие истинно. Постфикс while имеет ту же магическую обработку некоторых видов условий, что и префикс while. until делает обратное, он повторяет оператор, пока условие ложно (или пока условие ложно):

# Both of these count from 0 to 10.
print $i++ while $i <= 10;
print $j++ until $j >  10;

Модификаторы while и until имеют стандартную семантику «while цикла» (условие вычисляется сначала), за исключением случаев применения к do-БЛОКУ (или к оператору do-ПОДПРОГРАММЫ Perl4), в этом случае блок выполняется один раз перед вычислением условия.

Это сделано для того, чтобы вы могли писать циклы, такие как:

do {
    $line = <STDIN>;
    ...
} until !defined($line) || $line eq ".\n"

См. "do" в perlfunc. Обратите также внимание, что операторы управления циклами, описанные ниже, не будут работать в этой конструкции, потому что модификаторы не принимают метки циклов. Извините. Вы всегда можете поместить другой блок внутри него (для next/redo) или вокруг него (для last) для выполнения такого рода действий.

Для next или redo, используйте двойные фигурные скобки:

do {{
    next if $x == $y;
    # do something here
}} until $x++ > $z;

Для last, вам нужно быть более детальным и поставить фигурные скобки вокруг него:

{
    do {
        last if $x == $y**2;
        # do something here
    } while $x++ <= $z;
}

Если вам нужны оба next и last, вам нужно сделать оба, а также использовать метку цикла:

LOOP: {
    do {{
        next if $x == $y;
        last LOOP if $x == $y**2;
        # do something here
    }} until $x++ > $z;
}

ПРИМЕЧАНИЕ: Поведение my, state, или our, изменённых модификатором оператора, условием или конструкцией цикла (например, my $x if ...) является неопределённым. Значение переменной my может быть undef, любым ранее присвоенным значением или, возможно, чем-то ещё. Не полагайтесь на это. Будущие версии Perl могут вести себя иначе, чем версия Perl, которую вы используете. Здесь находятся драконы.

Модификатор when является экспериментальной функцией, впервые появившейся в Perl 5.14. Чтобы использовать его, вам нужно включить объявление use v5.14. (Технически, он требует только функции switch, но этот аспект не был доступен до 5.14.) Действует только внутри цикла foreach или блока given, он выполняет оператор только если умный соответствие $_ ~~ EXPR истинно. Если оператор выполняется, за ним следует next изнутри foreach и break изнутри given.

В текущей реализации цикл foreach может быть где угодно внутри динамической области видимости модификатора when, но должен находиться в лексической области видимости блока given. Это ограничение может быть ослаблено в будущих выпусках. См. "Операторы Switch" ниже.

Составные операторы

В Perl последовательность операторов, определяющая область видимости, называется блоком. Иногда блок ограничен файлом, содержащим его (в случае с требуемым файлом или программой в целом), а иногда блок ограничен областью строки (в случае с eval).

В общем случае, блок ограничен фигурными скобками, также известными как фигурные. Мы будем называть это синтаксическое построение БЛОКОМ. Поскольку фигурные скобки также являются синтаксисом для выражений конструкторов ссылок на хеши (см. perlref), вам иногда может потребоваться устранить неоднозначность, поместив ; сразу после открывающей фигурной скобки, чтобы Perl понял, что эта скобка — начало блока. Вам чаще потребуется устранить неоднозначность другим способом, поместив + непосредственно перед открывающей фигурной скобкой, чтобы заставить интерпретатор рассматривать её как выражение конструктора ссылок на хеш. Принято использовать эти механизмы устранения неоднозначности широко, не только когда Perl иначе мог бы сделать неправильный вывод.

Для управления потоком могут быть использованы следующие составные операторы:

if (EXPR) BLOCK
if (EXPR) BLOCK else BLOCK
if (EXPR) BLOCK elsif (EXPR) BLOCK ...
if (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK

unless (EXPR) BLOCK
unless (EXPR) BLOCK else BLOCK
unless (EXPR) BLOCK elsif (EXPR) BLOCK ...
unless (EXPR) BLOCK elsif (EXPR) BLOCK ... else BLOCK

given (EXPR) BLOCK

LABEL while (EXPR) BLOCK
LABEL while (EXPR) BLOCK continue BLOCK

LABEL until (EXPR) BLOCK
LABEL until (EXPR) BLOCK continue BLOCK

LABEL for (EXPR; EXPR; EXPR) BLOCK
LABEL for VAR (LIST) BLOCK
LABEL for VAR (LIST) BLOCK continue BLOCK

LABEL foreach (EXPR; EXPR; EXPR) BLOCK
LABEL foreach VAR (LIST) BLOCK
LABEL foreach VAR (LIST) BLOCK continue BLOCK

LABEL BLOCK
LABEL BLOCK continue BLOCK

PHASE BLOCK

Начиная с Perl 5.36, вы можете итерировать по нескольким значениям одновременно, указав список лексических переменных в скобках:

no warnings "experimental::for_list";
LABEL for my (VAR, VAR) (LIST) BLOCK
LABEL for my (VAR, VAR) (LIST) BLOCK continue BLOCK
LABEL foreach my (VAR, VAR) (LIST) BLOCK
LABEL foreach my (VAR, VAR) (LIST) BLOCK continue BLOCK

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

try BLOCK catch (VAR) BLOCK
try BLOCK catch (VAR) BLOCK finally BLOCK

Экспериментальный оператор given не включён по умолчанию; см. "Операторы выбора" ниже, чтобы узнать, как это сделать, и о связанных предостережениях.

В отличие от C и Pascal, в Perl все они определены в терминах БЛОКОВ, а не операторов. Это означает, что фигурные скобки обязательны — недопустимы висячие операторы. Если вы хотите записать условные операторы без фигурных скобок, есть несколько других способов сделать это. Все перечисленные ниже делают одно и то же:

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 прост. Поскольку блоки всегда ограничены фигурными скобками, никогда не возникает неоднозначности относительно того, с каким 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
}}

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

Форма while/if BLOCK BLOCK, доступная в Perl 4, больше недоступна. Замените все вхождения if BLOCK на if (do BLOCK).

Циклы For

Стиль циклов for Perl, аналогичный циклам C, работает как соответствующий цикл while; это означает, что следующее:

for ($i = 1; $i < 10; $i++) {
    ...
}

эквивалентно следующему:

$i = 1;
while ($i < 10) {
    ...
} continue {
    $i++;
}

Есть одно небольшое различие: если переменные объявлены с my в разделе инициализации for, область видимости этих переменных точно соответствует циклу for (тело цикла и разделы управления). Чтобы проиллюстрировать:

my $i = 'samba';
for (my $i = 1; $i <= 4; $i++) {
    print "$i\n";
}
print "$i\n";

при выполнении даёт:

1
2
3
4
samba

В качестве особого случая, если проверка в цикле for (или соответствующем цикле while) пустая, она обрабатывается как истинная. То есть оба

for (;;) {
    ...
}

и

while () {
    ...
}

обрабатываются как бесконечные циклы.

Помимо обычного итерирования по индексам массивов, for может быть использован во многих других интересных применениях. Вот один, который избегает проблемы, с которой вы сталкиваетесь, если явным образом проверяете конец файла на интерактивном дескрипторе файла, из-за чего программа, по-видимому, зависает.

$on_a_tty = -t STDIN && -t STDOUT;
sub prompt { print "yes? " if $on_a_tty }
for ( prompt(); <STDIN>; prompt() ) {
    # do something
}

Выражение условия цикла for получает ту же магическую обработку, что и readline и т.д., что и выражение условия цикла while.

Циклы Foreach

Цикл foreach перебирает обычное значение списка и устанавливает скалярную переменную VAR на каждый элемент списка по очереди. Если перед переменной стоит ключевое слово my, то она имеет лексическую область видимости и, следовательно, видна только внутри цикла. В противном случае переменная неявно локальна для цикла и восстанавливает своё прежнее значение при выходе из цикла. Если переменная была ранее объявлена с помощью my, она используется вместо глобальной, но всё ещё локальна для цикла. Это неявное локализирование происходит только для циклов, не являющихся циклами в стиле C.

Ключевое слово foreach фактически является синонимом ключевого слова for, поэтому вы можете использовать любое из них. Если VAR опущено, $_ устанавливается на каждое значение.

Если любой элемент LIST является lvalue, вы можете изменить его, изменив VAR внутри цикла. Обратно, если какой-либо элемент LIST не является lvalue, любая попытка изменить этот элемент не удастся. Иными словами, переменная индекса цикла foreach — это неявный псевдоним каждого элемента в списке, по которому вы перебираете.

Если какая-либо часть LIST является массивом, foreach будет очень сбит с толку, если вы добавите или удалите элементы внутри тела цикла, например, с помощью splice. Поэтому не делайте этого.

foreach вряд ли сделает то, что вы ожидаете, если VAR является привязанной или другой специальной переменной. Не делайте этого тоже.

Начиная с Perl 5.22, существует экспериментальная разновидность этого цикла, которая принимает переменную, предваряемую обратным слэшем для VAR, в этом случае элементы LIST должны быть ссылками. Переменная с обратным слэшем станет псевдонимом каждой ссылаемой позиции в списке LIST, которая должна быть правильного типа. Переменная не обязательно должна быть скалярной в этом случае, и за обратным слэшем может следовать my. Чтобы использовать этот формат, вы должны включить функцию refaliasing через use feature. (См. feature. См. также "Присваивание ссылкам" в perlref.)

Начиная с Perl 5.36, вы можете итерировать по нескольким значениям одновременно. Вы можете итерировать только с лексическими скалярами в качестве переменных итерации — в отличие от присваивания списков, невозможно использовать undef для обозначения значения, которое не требуется. Это ограничение текущей реализации и может быть изменено в будущем.

Если размер LIST не является точным кратным количеству переменных итерации, то на последней итерации "избыточные" переменные итерации — псевдонимы undef, как если бы LIST имел , undef добавленным столько раз, сколько необходимо, чтобы его длина стала точным кратным. Это происходит, независимо от того, является ли LIST литеральным списком или массивом — то есть массивы не расширяются, если их размер не кратен размеру итерации, в согласии с итерацией по массиву по одному элементу. Поскольку эти добавляемые элементы не являются lvalue, попытка изменить их не удастся, в согласии с поведением при переборе списка с литеральными undef. Если это не то поведение, которого вы ожидаете, то перед началом цикла либо явным образом расширьте массив, чтобы он стал точным кратным, либо явным образом бросьте исключение.

Примеры:

for (@ary) { s/foo/bar/ }

for my $elem (@elements) {
    $elem *= 2;
}

for $count (reverse(1..10), "BOOM") {
    print $count, "\n";
    sleep(1);
}

for (1..15) { print "Merry Christmas\n"; }

foreach $item (split(/:[\\\n:]*/, $ENV{TERMCAP})) {
    print "Item: $item\n";
}

use feature "refaliasing";
no warnings "experimental::refaliasing";
foreach \my %hash (@array_of_hash_references) {
    # do something with each %hash
}

foreach my ($foo, $bar, $baz) (@list) {
    # do something three-at-a-time
}

foreach my ($key, $value) (%hash) {
    # iterate over the hash
    # The hash is immediately copied to a flat list before the loop
    # starts. The list contains copies of keys but aliases of values.
    # This is the same behaviour as for $var (%hash) {...}
}

Вот как программист C мог бы закодировать определённый алгоритм на Perl:

for (my $i = 0; $i < @ary1; $i++) {
    for (my $j = 0; $j < @ary2; $j++) {
        if ($ary1[$i] > $ary2[$j]) {
            last; # can't go to outer :-(
        }
        $ary1[$i] += $ary2[$j];
    }
    # this is where that last takes me
}

А вот как программист Perl, более знакомый с этой конструкцией, мог бы сделать это:

OUTER: for my $wid (@ary1) {
INNER:   for my $jet (@ary2) {
            next OUTER if $wid > $jet;
            $wid += $jet;
         }
      }

Смотрите, насколько проще это стало? Это чище, безопаснее и быстрее. Это чище, потому что шума меньше. Это безопаснее, потому что, если позже в код будет добавлено что-то между внутренними и внешними циклами, новый код не будет случайно выполнен. next явно итерирует другой цикл, а не просто завершает внутренний. И это быстрее, потому что Perl выполняет оператор 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.

За блоками try и catch может по желанию следовать третий блок, вводимый ключевым словом finally. Этот третий блок выполняется после завершения остальной части конструкции.

try {
    call_a_function();
}
catch ($e) {
    warn "Unable to call; $e";
}
finally {
    print "Finished\n";
}

Блок finally эквивалентен использованию блока defer и будет вызван в тех же ситуациях; независимо от того, завершится ли блок try успешно, вызовет ли он исключение или передаст управление в другое место с помощью return, управления циклом или goto.

В отличие от блоков try и catch, блок finally не может return, goto или использовать какие-либо управляющие циклы. Значение последнего выражения игнорируется и не влияет на возвращаемое значение содержащей функции, даже если оно расположено последним в функции.

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

Основные блоки

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

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

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

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

Блоки defer

Блок, помеченный модификатором defer, обеспечивает раздел кода, который выполняется в более позднее время при выходе из области видимости.

Блок defer может появиться в любом месте, где разрешен обычный блок или другой оператор. Если поток выполнения достигнет этой инструкции, тело блока сохраняется на более позднее время, но не вызывается немедленно. Когда поток управления покидает содержащий блок по любой причине, этот сохранённый блок выполняется по пути. Это предоставляет возможность отложить выполнение до более позднего времени. Это аналогично синтаксису, предоставляемому некоторыми другими языками, часто использующими ключевые слова под названием try / finally.

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

use feature 'defer';

{
    say "This happens first";
    defer { say "This happens last"; }

    say "And this happens inbetween";
}

Если в одной области видимости содержится несколько блоков defer, они выполняются в порядке LIFO; последний достигнут — первый выполнен.

Код, сохранённый блоком defer, будет вызван, когда управление покинет свой содержащий блок из-за обычной передачи, явного return, исключений, сгенерированных в die или переданных функциями, вызванными им, goto, или любыми операторами управления циклом next, last или redo.

Если поток выполнения не достигнет оператора defer сам по себе, то его тело не сохраняется для последующего выполнения. (Это прямо противоположно коду, предоставляемому блоком фазера END, который всегда вставляется в очередь компилятором, независимо от того, достиг ли выполнения оператор, которому он был дан.)

use feature 'defer';

{
    defer { say "This will run"; }
    return;
    defer { say "This will not"; }
}

Исключения, сгенерированные кодом внутри блока defer, будут переданы вызывающей стороне так же, как и любые другие исключения, сгенерированные обычным кодом.

Если блок defer выполняется из-за сгенерированного исключения и сам генерирует другое исключение, не уточняется, что произойдёт, за исключением того, что вызывающая сторона определённо получит исключение.

Помимо генерации исключений, блок defer не может иначе изменить поток управления окружающего кода. В частности, он не может заставить содержащую функцию return, ни может goto метку, или управлять содержащим циклом с помощью next, last или redo. Однако, эти конструкции полностью разрешены внутри тела defer.

use feature 'defer';

{
    defer {
        foreach ( 1 .. 5 ) {
            last if $_ == 3;     # this is permitted
        }
    }
}

{
    foreach ( 6 .. 10 ) {
        defer {
            last if $_ == 8;     # this is not
        }
    }
}

Операторы switch

Начиная с Perl 5.10.1 (ну, 5.10.0, но он не работал правильно), можно сказать

use feature "switch";

чтобы включить экспериментальную функцию switch. Это основано на старой версии предложения Raku, но уже не похоже на конструкцию Raku. Вы также получаете функцию switch, когда заявляете, что ваш код предпочитает работать под версией Perl между 5.10 и 5.34. Например:

use v5.14;

В функции «switch» Perl получает экспериментальные ключевые слова given, when, default, continue, и break. Начиная с Perl 5.16, можно добавлять префикс CORE:: к ключевым словам switch, чтобы получить доступ к функции без оператора use feature. Ключевые слова given и when аналогичны switch и case в других языках — хотя continue нет — поэтому код в предыдущем разделе можно переписать как

use v5.10.1;
for ($var) {
    when (/^abc/) { $abc = 1 }
    when (/^def/) { $def = 1 }
    when (/^xyz/) { $xyz = 1 }
    default       { $nothing = 1 }
}

foreach — это способ без использования экспериментальной функции для установки 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 присваивает переменной $_ значение её темы.

Точно сказать, что делает аргумент EXPR для when, сложно, но, как правило, он пытается угадать, что вы хотите сделать. Иногда он интерпретируется как $_ ~~ EXPR, а иногда — нет. Его поведение также отличается, когда он лексически заключён в блок given, по сравнению с динамическим включением в цикл foreach. Правила слишком сложны для описания здесь. См. "Экспериментальные детали по given и when" позже.

Из-за неприятной ошибки в реализации given между Perl 5.10 и 5.16, в этих реализациях версия $_, управляемая given, является просто лексической копией оригинала, а не динамически связанным псевдонимом к оригиналу, как это было бы, если бы это был foreach или в соответствии с оригинальной и текущей спецификацией языка Raku. Эта ошибка была исправлена в Perl 5.18 (а лексическая версия $_ была удалена в Perl 5.24).

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

Goto

Хотя не для слабонервных, Perl поддерживает оператор goto. Существует три формы: goto-LABEL, goto-EXPR и goto-&NAME. Метка цикла фактически не является допустимой целью для 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 (это упрощает разбор), в то время как компилятор на самом деле знает, как искать escape-последовательности 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» считается очень экспериментальной (она также запланирована к удалению в perl 5.42.0); она может быть изменена без предварительного уведомления. В частности, 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 как smartsmartmatch.

Кроме того, 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" никогда не будет рассматриваться (хотя правила рекомендуют использовать smartmatch для "foo"). Для такого альтернативного случая ссылка на массив подойдёт, поскольку это инициирует smartmatching:

when ([qw(foo bar)] { ... }

Это в некоторой степени эквивалентно функции пропуска в операторе switch в стиле C (не путать с функцией пропуска в Perl — см. ниже), где один и тот же блок используется для нескольких case операторов.

Ещё одна полезная сокращённая запись: если в качестве аргумента функции given используется литеральный массив или хэш, он преобразуется в ссылку. Таким образом, given(@foo) эквивалентно given(\@foo), например.

default ведёт себя точно так же, как when(1 == 1), то есть всегда соответствует.

Прерывание

Вы можете использовать ключевое слово break для выхода из окружающего given блока. Каждый when блок неявно завершается break.

Пропускание

Вы можете использовать ключевое слово continue для пропуска от одного 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). Вы должны использовать стандартную переменную $_.

Отличия от Raku

Конструкции smartmatch и given/when Perl 5 несовместимы с их аналогами в Raku. Наиболее заметное и наименее важное отличие заключается в том, что в Perl 5 скобки необходимы вокруг аргумента given() и when() (за исключением случаев, когда последняя используется как модификатор оператора). Скобки в Raku всегда необязательны в конструкции управления, такой как if(), while(), или when(); они не могут быть сделаны необязательными в Perl 5 без значительного риска путаницы, поскольку Perl 5 будет интерпретировать выражение

given $foo {
    ...
}

будто аргумент given является элементом хэша %foo, интерпретируя фигурные скобки как синтаксис элементов хэша.

Однако существует много других различий. Например, это работает в Perl 5:

use v5.12;
my @primary = ("red", "blue", "green");

if (@primary ~~ "red") {
    say "primary smartmatches red";
}

if ("red" ~~ @primary) {
    say "red smartmatches primary";
}

say "that's all, folks!";

Но это совсем не работает в Raku. Вместо этого вы должны использовать (параллелизуемый) оператор any.

if any(@primary) eq "red" {
    say "primary smartmatches red";
}

if "red" eq any(@primary) {
    say "red smartmatches primary";
}

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

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

© 1993–2023 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.38.0/perlsyn

Spec-Zone.ru

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