Spec-Zone.ru › Perl 5.38

perlsub

СОДЕРЖАНИЕ

  • ИМЯ
  • СИНОПС
  • ОПИСАНИЕ
    • Подписи
    • Переменные-только для подпрограммы с помощью my()
    • Постоянные переменные-только для подпрограммы
      • Постоянные переменные с помощью state()
      • Постоянные переменные с замыканиями
    • Временные значения с помощью local()
      • Грамматическая заметка о local()
      • Локализация специальных переменных
      • Локализация глобов
      • Локализация элементов составных типов
      • Локализованное удаление элементов составных типов
    • Подпрограммы-lvalue
    • Лексические подпрограммы
      • Подпрограмма state vs подпрограмма my
      • Подпрограммы our
    • Передача записей таблицы символов (typeglobs)
    • Когда всё ещё следует использовать local()
    • Передача по ссылке
    • Прототипы
    • Постоянные функции
    • Переопределение встроенных функций
    • Автозагрузка
    • Атрибуты подпрограмм
  • СМОТРИТЕ ТАКЖЕ

ИМЯ

perlsub - Подпрограммы Perl

СИНОПС

Для объявления подпрограмм:

sub NAME;                       # A "forward" declaration.
sub NAME(PROTO);                #  ditto, but with prototypes
sub NAME : ATTRS;               #  with attributes
sub NAME(PROTO) : ATTRS;        #  with attributes and prototypes

sub NAME BLOCK                  # A declaration and a definition.
sub NAME(PROTO) BLOCK           #  ditto, but with prototypes
sub NAME : ATTRS BLOCK          #  with attributes
sub NAME(PROTO) : ATTRS BLOCK   #  with prototypes and attributes

use feature 'signatures';
sub NAME(SIG) BLOCK                     # with signature
sub NAME :ATTRS (SIG) BLOCK             # with signature, attributes
sub NAME :prototype(PROTO) (SIG) BLOCK  # with signature, prototype

Для определения анонимной подпрограммы во время выполнения:

$subref = sub BLOCK;                    # no proto
$subref = sub (PROTO) BLOCK;            # with proto
$subref = sub : ATTRS BLOCK;            # with attributes
$subref = sub (PROTO) : ATTRS BLOCK;    # with proto and attributes

use feature 'signatures';
$subref = sub (SIG) BLOCK;          # with signature
$subref = sub : ATTRS(SIG) BLOCK;   # with signature, attributes

Для импорта подпрограмм:

use MODULE qw(NAME1 NAME2 NAME3);

Для вызова подпрограмм:

NAME(LIST);     # & is optional with parentheses.
NAME LIST;      # Parentheses optional if predeclared/imported.
&NAME(LIST);    # Circumvent prototypes.
&NAME;          # Makes current @_ visible to called subroutine.

ОПИСАНИЕ

Как и во многих языках, Perl предоставляет возможность определять пользовательские подпрограммы. Они могут быть расположены где угодно в основной программе, загружены из других файлов с помощью ключевых слов do, require, или use, или созданы на лету с помощью eval или анонимных подпрограмм. Вы даже можете вызвать функцию косвенно, используя переменную, содержащую её имя, или ссылку на код.

Модель Perl для вызова функций и возвращаемых значений проста: все функции принимают в качестве параметров один единственный плоский список скаляров, и все функции также возвращают своему вызывающему объекту один единственный плоский список скаляров. Любые массивы или хэши в этих списках вызовов и возвратов будут сжаты, потеряв свою идентичность, но вы всегда можете использовать передачу по ссылке, чтобы этого избежать. Оба списка вызовов и возвратов могут содержать столько или так мало скалярных элементов, сколько вам нужно. (Часто функция без явного оператора return называется подпрограммой, но с точки зрения Perl никакой разницы нет.)

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

В подпрограмме, не использующей подписи, все переданные аргументы появляются в массиве @_. Следовательно, если вы вызвали функцию с двумя аргументами, они будут храниться в $_[0] и $_[1]. Массив @_ — это локальный массив, но его элементы являются псевдонимами фактических скалярных параметров. В частности, если элемент $_[0] обновляется, соответствующий аргумент обновляется (или возникает ошибка, если он не может быть обновлён). Если аргументом является элемент массива или хэша, который не существовал при вызове функции, этот элемент создаётся только тогда (и если) он модифицируется или к нему берётся ссылка. (В некоторых более ранних версиях Perl элемент создавался независимо от того, присваивался ли он.) Присваивание всему массиву @_ удаляет это псевдонимирование и не обновляет никакие аргументы.

Когда не используются подписи, Perl не предоставляет других способов создания именованных формальных параметров. На практике всё сводится к присваиванию в my() список этих параметров. Переменные, которые не объявлены как частные, являются глобальными переменными. Подробности создания частных переменных см. в "Переменные-только для подпрограммы с помощью my()" и "Временные значения с помощью local()". Чтобы создать защищённую среду для набора функций в отдельном пакете (и, вероятно, в отдельном файле), см. "Пакеты" в perlmod.

Оператор return может использоваться для выхода из подпрограммы, необязательно указав возвращаемое значение, которое будет обработано в соответствующем контексте (список, скаляр или пустое значение) в зависимости от контекста вызова подпрограммы. Если вы не указываете возвращаемое значение, подпрограмма возвращает пустой список в контексте списка, неопределённое значение в скалярном контексте или ничего в пустом контексте. Если вы возвращаете один или несколько агрегатов (массивы и хэши), они будут сплющены вместе в один большой неразличимый список.

Если return не найдено, и последняя инструкция — это выражение, его значение возвращается. Если последняя инструкция — это структура управления циклом, например, foreach или while, возвращаемое значение не определено. Пустая подпрограмма возвращает пустой список.

Пример:

sub max {
    my $max = shift(@_);
    foreach $foo (@_) {
        $max = $foo if $max < $foo;
    }
    return $max;
}
$bestday = max($mon,$tue,$wed,$thu,$fri);

Пример:

# get a line, combining continuation lines
#  that start with whitespace

sub get_line {
    $thisline = $lookahead;  # global variables!
    LINE: while (defined($lookahead = <STDIN>)) {
        if ($lookahead =~ /^[ \t]/) {
            $thisline .= $lookahead;
        }
        else {
            last LINE;
        }
    }
    return $thisline;
}

$lookahead = <STDIN>;       # get first line
while (defined($line = get_line())) {
    ...
}

Присвоение списку частных переменных для именования аргументов:

sub maybeset {
    my($key, $value) = @_;
    $Foo{$key} = $value unless $Foo{$key};
}

Поскольку присваивание копирует значения, это также приводит к преобразованию передачи по ссылке в передачу по значению. В противном случае функция свободна выполнять изменения на месте в @_ и изменять значения вызывающего объекта.

upcase_in($v1, $v2);  # this changes $v1 and $v2
sub upcase_in {
    for (@_) { tr/a-z/A-Z/ }
}

Конечно, вам не разрешено изменять константы таким образом. Если аргументом являлась константа, и вы пытались её изменить, это вызовет исключение (вероятно, фатальное). Например, это не сработает:

upcase_in("frederick");

Было бы намного безопаснее, если бы функция upcase_in() возвращала копию своих параметров, а не изменяла их на месте:

($v3, $v4) = upcase($v1, $v2);  # this doesn't change $v1 and $v2
sub upcase {
    return unless defined wantarray;  # void context, do nothing
    my @parms = @_;
    for (@parms) { tr/a-z/A-Z/ }
    return wantarray ? @parms : $parms[0];
}

Обратите внимание, как эта (не прототипированная) функция не заботится о том, были ли ей переданы реальные скаляры или массивы. Perl рассматривает все аргументы как один большой, длинный, плоский список параметров в @_. В этом месте преимущества простого стиля передачи аргументов Perl очевидны. Функция upcase() будет работать безупречно без изменения определения upcase(), даже если мы передадим ей такие вещи:

@newlist   = upcase(@list1, @list2);
@newlist   = upcase( split /:/, $var );

Однако не стоит пытаться сделать следующее:

(@x, @y)   = upcase(@list1, @list2);

Как и сплюснутый входящий список параметров, список возврата также сплющивается при возврате. Так вы просто сохранили всё в @x и сделали @y пустым. Смотрите "Передача по ссылке" для альтернатив.

Подпрограмму можно вызвать с явным & префиксом. & необязательны в современном Perl, как и скобки, если подпрограмма была предопределена. & не является необязательным, когда вы просто называете подпрограмму, например, когда она используется в качестве аргумента для defined() или undef(). Она также не является необязательной, когда вы хотите выполнить косвенный вызов подпрограммы с именем подпрограммы или ссылкой, используя конструкции &$subref() или &{$subref}(), хотя запись $subref->() решает эту проблему. Смотрите perlref для получения более подробной информации об этом.

Подпрограммы могут вызываться рекурсивно. Если подпрограмма вызывается в виде & , список аргументов необязателен, и если он опущен, массив @_ для подпрограммы не создаётся: массив @_ на момент вызова виден для подпрограммы вместо него. Это механизм повышения эффективности, которого новичкам, возможно, следует избегать.

&foo(1,2,3);        # pass three arguments
foo(1,2,3);         # the same

foo();              # pass a null list
&foo();             # the same

&foo;               # foo() get current args, like foo(@_) !!
use strict 'subs';
foo;                # like foo() iff sub foo predeclared, else
                    # a compile-time error
no strict 'subs';
foo;                # like foo() iff sub foo predeclared, else
                    # a literal string "foo"

Форма & не только делает список аргументов необязательным, но также отключает проверку прототипов аргументов, которые вы предоставляете. Это отчасти связано с историческими причинами, а отчасти для удобства обмана, если вы знаете, что делаете. См. "Прототипы" ниже.

С Perl 5.16.0 доступен токен __SUB__ в use feature 'current_sub' и use v5.16. Он будет соответствовать ссылке на текущую выполняющуюся подпрограмму, что позволяет выполнять рекурсивные вызовы без знания имени вашей подпрограммы.

use v5.16;
my $factorial = sub {
    my ($x) = @_;
    return 1 if $x == 1;
    return($x * __SUB__->( $x - 1 ) );
};

Поведение __SUB__ внутри блока кода регулярного выражения (например, /(?{...})/) может измениться.

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

документировано позже в этом документе

AUTOLOAD

документировано в perlmod

CLONE, CLONE_SKIP

документировано в perlobj

DESTROY, DOES

документировано в perltie

BINMODE, CLEAR, CLOSE, DELETE, DESTROY, EOF, EXISTS, EXTEND, FETCH, FETCHSIZE, FILENO, FIRSTKEY, GETC, NEXTKEY, OPEN, POP, PRINT, PRINTF, PUSH, READ, READLINE, SCALAR, SEEK, SHIFT, SPLICE, STORE, STORESIZE, TELL, TIEARRAY, TIEHANDLE, TIEHASH, TIESCALAR, UNSHIFT, UNTIE, WRITE

документировано в PerlIO::via

BINMODE, CLEARERR, CLOSE, EOF, ERROR, FDOPEN, FILENO, FILL, FLUSH, OPEN, POPPED, PUSHED, READ, SEEK, SETLINEBUF, SYSOPEN, TELL, UNREAD, UTF8, WRITE

документировано в perlfunc

import, unimport, INC

документировано в UNIVERSAL

VERSION

документировано в perldebguts

DB::DB, DB::sub, DB::lsub, DB::goto, DB::postponed

недокументировано, используется внутри функции overload

любые, начинающиеся с (

Подпрограммы BEGIN, UNITCHECK, CHECK, INIT и END - это не столько подпрограммы, сколько именованные специальные блоки кода, из которых в пакете можно иметь более одного, и которые вы не можете вызвать явно. См. "BEGIN, UNITCHECK, CHECK, INIT и END" в perlmod

Подписи

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

Эта возможность должна быть включена, прежде чем она сможет быть использована. Она включается автоматически объявлением use v5.36 (или выше) или более прямо use feature 'signatures', в текущем области видимости.

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

Например,

sub foo :lvalue ($x, $y = 1, @z) { .... }

Подпись объявляет лексические переменные, которые находятся в области видимости блока. Когда подпрограмма вызывается, подпись получает управление в первую очередь. Она заполняет переменные подписи из списка аргументов, которые были переданы. Если список аргументов не соответствует требованиям подписи, то будет выброшено исключение. После завершения обработки подписи управление переходит к блоку.

Позиционные параметры обрабатываются простым указанием имен скалярных переменных в подписи. Например,

sub foo ($left, $right) {
    return $left + $right;
}

принимает два позиционных параметра, которые должны быть заполнены во время выполнения двумя аргументами. По умолчанию параметры являются обязательными, и запрещено передавать больше аргументов, чем ожидается. Таким образом, вышеприведенное эквивалентно

sub foo {
    die "Too many arguments for subroutine" unless @_ <= 2;
    die "Too few arguments for subroutine" unless @_ >= 2;
    my $left = $_[0];
    my $right = $_[1];
    return $left + $right;
}

Аргумент можно пропустить, опуская основную часть имени из объявления параметра, оставив только знак $. Например,

sub foo ($first, $, $third) {
    return "first=$first, third=$third";
}

Хотя пропущенный аргумент не попадает в переменную, вызывающей стороне все равно необходимо его передать.

Позиционный параметр делается необязательным, присваивая ему значение по умолчанию, отделённое от имени параметра символом =:

sub foo ($left, $right = 0) {
    return $left + $right;
}

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

my $auto_id = 0;
sub foo ($thing, $id = $auto_id++) {
    print "$thing has ID $id";
}

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

sub foo ($first_name, $surname, $nickname = $first_name) {
    print "$first_name $surname is known as \"$nickname\"";
}

Выражение значения по умолчанию также может быть записано с использованием оператора //=, где оно будет вычислено и использовано, если вызывающая сторона пропустила значение или предоставленное значение было undef.

sub foo ($name //= "world") {
    print "Hello, $name";
}

foo(undef);  # will print "Hello, world"

Аналогично, оператор ||= может использоваться для предоставления выражения значения по умолчанию, которое будет использоваться всякий раз, когда вызывающая сторона предоставила ложное значение (и помните, что отсутствующее или undef значение также являются ложными).

sub foo ($x ||= 10) {
    return 5 + $x;
}

Необязательный параметр может быть безымянным, как и обязательный параметр. Например,

sub foo ($thing, $ = 1) {
    print $thing;
}

Значение по умолчанию параметра все равно будет вычислено, если соответствующий аргумент не указан, даже если значение никуда не будет сохранено. Это на случай, если вычисление имеет важные побочные эффекты. Однако оно будет вычислено в контексте без значения, поэтому, если у него нет побочных эффектов и оно не тривиально, он сгенерирует предупреждение, если категория предупреждений "без значения" включена. Если значение по умолчанию безымянного необязательного параметра не важно, его можно опустить, точно так же как имя параметра:

sub foo ($thing, $=) {
    print $thing;
}

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

После позиционных параметров дополнительные аргументы могут быть получены в параметре захвата. Самый простой вариант — это просто массив переменных:

sub foo ($filter, @inputs) {
    print $filter->($_) foreach @inputs;
}

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

sub foo ($thing, @) {
    print $thing;
}

Вместо этого параметр захвата может быть хэшем, в котором аргументы интерпретируются как чередующиеся ключи и значения. Должно быть столько же ключей, сколько значений: если есть нечётное количество аргументов, будет выброшено исключение. Ключи будут приведены к строковому типу, и если есть дубликаты, то более позднее вхождение имеет приоритет над более ранним, как и при стандартном построении хэша.

sub foo ($filter, %inputs) {
    print $filter->($_, $inputs{$_}) foreach sort keys %inputs;
}

Параметр захвата хэша может быть безымянным, как и другие типы параметров. Он по-прежнему требует, чтобы количество аргументов, доступных ему, было чётным, даже если они не помещаются в переменную.

sub foo ($thing, %) {
    print $thing;
}

Параметр захвата, массив или хэш, должен быть последним элементом в подписи. Он может следовать за обязательными и необязательными позиционными параметрами; он также может быть единственным элементом в подписи. У параметров захвата не может быть значений по умолчанию: если для них не передано никаких аргументов, вы получите пустой массив или пустой хэш.

Подпись может быть полностью пустой, в этом случае она только проверяет, что вызывающая сторона не передала никаких аргументов:

sub foo () {
    return 123;
}

До Perl 5.36 они считались экспериментальными и генерировали предупреждение в категории experimental::signatures. Начиная с Perl 5.36 этого больше не происходит, хотя категория предупреждений всё ещё существует для обратной совместимости с кодом, который пытается отключить её с помощью оператора, например:

no warnings 'experimental::signatures';

В текущей реализации Perl, при использовании подписи, аргументы по-прежнему доступны и в специальной массиве переменных @_. Однако доступ к ним через этот массив теперь не рекомендуется и не следует использовать в недавно написанном коде, поскольку эта возможность может измениться в будущей версии. Код, который пытается получить доступ к массиву @_, будет генерировать предупреждения в категории experimental::args_array_with_signatures при компиляции:

sub f ($x) {
    # This line emits the warning seen below
    print "Arguments are @_";
}
Use of @_ in join or string with signatured subroutine is
experimental at ...

Есть разница между двумя способами доступа к аргументам: @_ ссылается на аргументы, но переменные подписи получают копии аргументов. Таким образом, запись в переменную подписи изменяет только эту переменную и не влияет на переменные вызывающей стороны, но запись в элемент @_ изменяет то, что вызывающая сторона использовала для передачи этого аргумента.

Возможна потенциальная синтаксическая неоднозначность между подписями и прототипами (см. "Прототипы"), поскольку оба начинаются с открывающей скобки и оба могут появляться в одних и тех же местах, например, сразу после имени в объявлении подпрограммы. По историческим причинам, когда подписи отключены, любая открывающая скобка в таком контексте будет вызывать очень снисходительную обработку прототипов. В большинстве случаев подписи будут интерпретироваться как прототипы, но не будут являться валидными прототипами. (Валидный прототип не может содержать никаких буквенных символов.) Это приведёт к несколько запутанным сообщениям об ошибках.

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

sub foo :prototype($) { $_[0] }

Совершенно возможно, что подпрограмма имеет как прототип, так и подпись. Они выполняют разные задачи: прототип влияет на компиляцию вызовов подпрограммы, а подпись помещает значения аргументов в лексические переменные во время выполнения. Поэтому вы можете написать

sub foo :prototype($$) ($left, $right) {
    return $left + $right;
}

Атрибут прототипа и любые другие атрибуты должны предшествовать подписи. Подпись всегда непосредственно предшествует блоку тела подпрограммы.

Частные переменные с помощью my()

Синопсис:

my $foo;            # declare $foo lexically local
my (@wid, %get);    # declare list of variables local
my $foo = "flurp";  # declare $foo lexical, and init it
my @oof = @bar;     # declare @oof lexical, and init it
my $x : Foo = $y;   # similar, with an attribute applied

ПРЕДУПРЕЖДЕНИЕ: Использование списков атрибутов в объявлениях my всё ещё находится в стадии развития. Текущая семантика и интерфейс могут быть изменены. См. атрибуты и Attribute::Handlers.

Оператор my объявляет перечисленные переменные как лексически ограниченные текущим блоком, условным (if/unless/elsif/else), циклом (for/foreach/while/until/continue), подпрограммой, eval, или eval, или файлом. Если перечислено более одного значения, список должен быть помещён в скобки. Все перечисленные элементы должны быть допустимыми lvalue. Лексически ограничены только идентификаторы, состоящие из букв и цифр — магические встроенные функции, такие как $/, в настоящее время должны быть local с использованием local.

В отличие от динамических переменных, созданных оператором local, лексические переменные, объявленные с помощью оператора my, полностью скрыты от внешнего мира, включая вызываемые подпрограммы. Это справедливо, если это одна и та же подпрограмма, вызываемая из себя или извне — каждый вызов получает свою собственную копию.

Это не означает, что переменная my, объявленная в статически окружающем лексическом пространстве видимости, будет невидимой. Только динамические области видимости отрезаются. Например, функция bumpx() ниже имеет доступ к лексической переменной $x, потому что как my, так и sub произошли в той же области видимости, предположительно, в области видимости файла.

my $x = 10;
sub bumpx { $x++ }

Однако, подпрограмма eval() может видеть лексические переменные области видимости, в которой она вычисляется, при условии, что имена не скрыты объявлениями внутри самой eval(). См. perlref.

Список параметров для my() может быть присвоен, если это необходимо, что позволяет инициализировать переменные. (Если для конкретной переменной не указано начальное значение, она создаётся с неопределённым значением). Обычно это используется для именования входных параметров подпрограммы. Примеры:

$arg = "fred";          # "global" variable
$n = cube_root(27);
print "$arg thinks the root is $n\n";
# outputs: fred thinks the root is 3

sub cube_root {
    my $arg = shift;  # name doesn't matter
    $arg **= 1/3;
    return $arg;
}

Оператор my является просто модификатором, к которому можно присвоить значение. Таким образом, когда вы присваиваете значения переменным в списке аргументов, my не меняет, рассматриваются ли эти переменные как скаляр или массив. Следовательно,

my ($foo) = <STDIN>;                # WRONG?
my @FOO = <STDIN>;

обе обеспечивают контекст списка для правой части, тогда как

my $foo = <STDIN>;

обеспечивает контекст скаляра. Но следующее объявляет только одну переменную:

my $foo, $bar = 1;                  # WRONG

Это имеет тот же эффект, что и

my $foo;
$bar = 1;

Объявленная переменная не вводится (не видна) до выполнения текущего оператора. Таким образом,

my $x = $x;

может быть использовано для инициализации новой $x значением старой $x, и выражение

my $x = 123 and $x == 123

ложно, если старое $x не имело значения 123.

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

while (my $line = <>) {
    $line = lc $line;
} continue {
    print $line;
}

область видимости $line простирается от её объявления до остальной части конструкции цикла (включая continue предложение), но не выходит за её пределы. Аналогично, в условном операторе

if ((my $answer = <STDIN>) =~ /^yes$/i) {
    user_agrees();
} elsif ($answer =~ /^no$/i) {
    user_disagrees();
} else {
    chomp $answer;
    die "'$answer' is neither 'yes' nor 'no'";
}

область видимости $answer простирается от её объявления до остальной части этого условного оператора, включая любые elsif и else предложения, но не выходит за её пределы. Смотрите раздел «Простые операторы» в perlsyn для информации о области видимости переменных в операторах с модификаторами.

Цикл foreach по умолчанию ограничивает переменную индекса динамически по аналогии с local. Однако, если переменная индекса имеет префикс ключевое слово my, или уже существует лексическая переменная с таким же именем в области видимости, то вместо этого создаётся новая лексическая переменная. Таким образом, в цикле

for my $i (1, 2, 3) {
    some_function();
}

область видимости $i простирается до конца цикла, но не выходит за его пределы, делая значение $i недоступным внутри some_function().

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

use strict 'vars';

тогда любая переменная, упомянутая отсюда до конца окружающего блока, должна либо ссылаться на лексическую переменную, быть предварительно объявлена через our или use vars, либо же должна быть полностью квалифицирована с именем пакета. В противном случае возникает ошибка компиляции. Внутренний блок может аннулировать это с помощью no strict 'vars'.

Оператор my имеет как эффект времени компиляции, так и эффект времени выполнения. Во время компиляции компилятор обращает на него внимание. Основная полезность этого заключается в подавлении use strict 'vars', но это также необходимо для генерации замыканий, как подробно описано в perlref. Однако фактическая инициализация откладывается до времени выполнения, поэтому она выполняется в соответствующее время, например, каждый раз в цикле.

Переменные, объявленные с помощью my не являются частью любого пакета и поэтому никогда не квалифицируются полностью с именем пакета. В частности, вам не разрешается пытаться сделать переменную пакета (или другую глобальную) лексической:

my $pack::var;      # ERROR!  Illegal syntax

Фактически, динамическая переменная (также известная как переменная пакета или глобальная переменная) по-прежнему доступна с помощью полностью квалифицированной :: нотации, даже если лексическая переменная с тем же именем также видна:

package main;
local $x = 10;
my    $x = 20;
print "$x and $::x\n";

Это выведет 20 и 10.

Можно объявлять переменные my в самой внешней области видимости файла, чтобы скрыть такие идентификаторы от внешнего мира. Это похоже по духу на статические переменные языка C, используемые на уровне файла. Для этого с подпрограммой необходимо использовать замыкание (анонимную функцию, которая обращается к окружающим лексическим переменным). Если вы хотите создать закрытую подпрограмму, которую нельзя вызвать извне этого блока, она может объявить лексическую переменную, содержащую ссылку на анонимную подпрограмму:

my $secret_version = '1.001-beta';
my $secret_sub = sub { print $secret_version };
&$secret_sub();

До тех пор, пока ссылка не возвращается никакой функцией внутри модуля, никакой внешний модуль не увидит подпрограмму, поскольку её имя не находится в таблице символов любого пакета. Помните, что её действительно не называют $some_pack::secret_version или как-либо ещё; это просто $secret_version, неквалифицированная и неквалифицируемая.

Однако это не работает с методами объектов; все методы объектов должны быть в таблице символов какого-либо пакета, чтобы их можно было найти. См. "Шаблоны функций" в perlref для обходного пути.

Постоянные частные переменные

Есть два способа создания постоянных частных переменных в Perl 5.10. Во-первых, вы можете просто использовать функцию state. Или вы можете использовать замыкания, если хотите сохранить совместимость с версиями, более старыми чем 5.10.

Постоянные переменные с помощью state()

Начиная с Perl 5.10.0, вы можете объявлять переменные с помощью ключевого слова state вместо my. Для этого, однако, вы должны были предварительно включить эту функцию, либо используя прагму feature, либо используя -E для однострочных операторов (см. feature). Начиная с Perl 5.16, форма CORE::state не требует прагмы feature.

Ключевое слово state создаёт лексическую переменную (с теми же правилами области видимости, что и my ), которая сохраняется между вызовами подпрограммы. Если переменная state находится внутри анонимной подпрограммы, то каждая копия подпрограммы имеет свою собственную копию переменной state. Однако, значение переменной state всё ещё сохраняется между вызовами той же копии анонимной подпрограммы. (Не забудьте, что sub { ... } создаёт новую подпрограмму каждый раз при выполнении).

Например, следующий код поддерживает частный счётчик, увеличивающийся при каждом вызове функции gimme_another():

use feature 'state';
sub gimme_another { state $x; return ++$x }

И этот пример использует анонимные подпрограммы для создания отдельных счётчиков:

use feature 'state';
sub create_counter {
    return sub { state $x; return ++$x }
}

Кроме того, так как $x является лексической, она недоступна и не может быть изменена каким-либо кодом Perl вне.

При комбинировании с объявлением переменной простое присваивание переменным state (как в state $x = 42) выполняется только в первый раз. При последующем выполнении таких операторов присваивание игнорируется. Поведение присваивания к объявлениям state, где левая часть присваивания включает скобки, в настоящее время не определено.

Постоянные переменные с замыканиями

Просто потому, что лексическая переменная лексически (также называемая статически) ограничена своим окружающим блоком, eval, или do ФАЙЛ, это не означает, что внутри функции она работает так же, как статическая переменная C. Обычно она работает больше как автоматическая переменная C, но с неявным удалением мусора.

В отличие от локальных переменных в C или C++, лексические переменные Perl не обязательно перерабатываются, просто потому, что их область видимости закончилась. Если что-то более постоянное всё ещё обращается к лексической переменной, она будет существовать. Пока что-то ещё ссылается на лексическую переменную, она не будет освобождена — так и должно быть. Вы не захотите, чтобы память освобождалась, пока вы её не закончите использовать, или оставалась после того, как вы закончили её использовать. Автоматическое управление памятью заботится об этом за вас.

Это означает, что вы можете передавать или сохранять ссылки на лексические переменные, в то время как возвращение указателя на автоматическую переменную C — это серьёзная ошибка. Это также даёт нам способ имитировать статические переменные функций C. Вот механизм, позволяющий функции иметь частные переменные с лексической областью видимости и статическим сроком жизни. Если вы хотите создать что-то вроде статических переменных C, просто поместите всю функцию в дополнительный блок и поместите статическую переменную за пределами функции, но внутри блока.

{
    my $secret_val = 0;
    sub gimme_another {
        return ++$secret_val;
    }
}
# $secret_val now becomes unreachable by the outside
# world, but retains its value between calls to gimme_another

Если эта функция подключается из отдельного файла через require или use, то это, вероятно, нормально. Если всё находится в основной программе, вам нужно обеспечить выполнение my в начале, либо поместив весь блок над основной программой, либо, скорее всего, поместив просто блок кода BEGIN вокруг него, чтобы убедиться, что он выполняется до запуска программы:

BEGIN {
    my $secret_val = 0;
    sub gimme_another {
        return ++$secret_val;
    }
}

См. "BEGIN, UNITCHECK, CHECK, INIT и END" в perlmod о специальных блоках триггерного кода, BEGIN, UNITCHECK, CHECK, INIT и END.

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

Временные значения с помощью local()

ПРЕДУПРЕЖДЕНИЕ: В общем случае, вы должны использовать my вместо local, потому что это быстрее и безопаснее. Исключение составляют глобальные символы пунктуации, глобальные файловые дескрипторы и форматы, а также прямое манипулирование самой таблицей символов Perl. local в основном используется, когда текущее значение переменной должно быть видно вызываемым подпрограммам.

Синопсис:

# localization of values

local $foo;                # make $foo dynamically local
local (@wid, %get);        # make list of variables local
local $foo = "flurp";      # make $foo dynamic, and init it
local @oof = @bar;        # make @oof dynamic, and init it

local $hash{key} = "val";  # sets a local value for this hash entry
delete local $hash{key};   # delete this entry for the current block
local ($cond ? $v1 : $v2); # several types of lvalues support
                           # localization

# localization of symbols

local *FH;                 # localize $FH, @FH, %FH, &FH  ...
local *merlyn = *randal;   # now $merlyn is really $randal, plus
                           #     @merlyn is really @randal, etc
local *merlyn = 'randal';  # SAME THING: promote 'randal' to *randal
local *merlyn = \$randal;  # just alias $merlyn, not @merlyn etc

Оператор local изменяет перечисленные переменные, чтобы они были «локальными» для окружающего блока, eval, или do FILE—и для любой подпрограммы, вызываемой из этого блока. Оператор local просто присваивает временные значения глобальным (то есть пакетным) переменным. Он не создаёт локальную переменную. Это известно как динамическое область действия. Лексическое область действия достигается с помощью my, который работает больше как авто-декларации в C.

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

Если оператору local передаётся более одной переменной или выражения, они должны быть заключены в скобки. Этот оператор работает, сохраняя текущие значения этих переменных в списке аргументов на скрытом стеке и восстанавливая их при выходе из блока, подпрограммы или eval. Это означает, что вызываемые подпрограммы также могут ссылаться на локальную переменную, но не на глобальную. Список аргументов можно присвоить, если нужно, что позволяет инициализировать локальные переменные. (Если для конкретной переменной нет инициализатора, она создаётся с неопределённым значением.)

Поскольку local — оператор выполнения, он выполняется каждый раз при прохождении цикла. Следовательно, более эффективно локализовать переменные вне цикла.

Замечание по грамматике local()

Оператор local — это просто модификатор выражения lvalue. Когда вы присваиваете значение локализованной переменной, оператор local не изменяет, рассматривается ли его список как скаляр или массив. Таким образом

local($foo) = <STDIN>;
local @FOO = <STDIN>;

оба обеспечивают контекст списка для правой части, в то время как

local $foo = <STDIN>;

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

Локализация специальных переменных

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

Эта функция позволяет работать с таким кодом:

# Read the whole contents of FILE in $slurp
{ local $/ = undef; $slurp = <FILE>; }

Обратите внимание, что это ограничивает локализацию некоторых значений; например, следующая команда завершается ошибкой (с Perl 5.10.0) с ошибкой Попытка изменения неизменяемого значения, поскольку переменная $1 магическая и только для чтения:

local $1 = 2;

Исключением является стандартная скалярная переменная: начиная с Perl 5.14 local($_) всегда удаляет всю магию из $_, чтобы можно было безопасно повторно использовать $_ в подпрограмме.

ПРЕДУПРЕЖДЕНИЕ: Локализация связанных массивов и хешей в настоящее время не работает так, как описано. Это будет исправлено в будущих версиях Perl; в то время следует избегать кода, который полагается на какое-либо конкретное поведение локализации связанных массивов или хешей (локализация отдельных элементов всё ещё разрешена). Более подробную информацию см. в "Localising Tied Arrays and Hashes Is Broken" в perl58delta.

Локализация глобов

Конструкция

local *name;

создаёт новую запись в таблице символов для глоба name в текущем пакете. Это означает, что все переменные в его слоте глоба ($name, @name, %name, &name и name файловый дескриптор) динамически сбрасываются.

Это подразумевает, среди прочего, что любая магия, в конечном итоге связанная с этими переменными, теряется локально. Другими словами, local */ не повлияет на внутреннее значение разделителя входной записи.

Локализация элементов составных типов

Стоит также отметить, что происходит при локализации элемента составного типа (т.е. элемента массива или хеша). В этом случае элемент локализуется по имени. Это означает, что когда область действия локализации заканчивается, сохранённое значение будет восстановлено в элементе хеша с ключом, указанным в local(), или элементе массива с индексом, указанным в local(). Если этот элемент был удалён во время действия локализации (например, с помощью delete() из хеша или shift() из массива), он снова появится, возможно, увеличивая массив и заполняя пропущенные элементы undef. Например, если вы напишете

%hash = ( 'This' => 'is', 'a' => 'test' );
@ary  = ( 0..5 );
{
    local($ary[5]) = 6;
    local($hash{'a'}) = 'drill';
    while (my $e = pop(@ary)) {
        print "$e . . .\n";
        last unless $e > 3;
    }
    if (@ary) {
        $hash{'only a'} = 'test';
        delete $hash{'a'};
    }
}
print join(' ', map { "$_ $hash{$_}" } sort keys %hash),".\n";
print "The array has ",scalar(@ary)," elements: ",
    join(', ', map { defined $_ ? $_ : 'undef' } @ary),"\n";

Perl выведет

6 . . .
4 . . .
3 . . .
This is a test only a test.
The array has 6 elements: 0, 1, 2, undef, undef, 5

Поведение оператора local() для несуществующих элементов составных типов может измениться в будущем. Поведение оператора local() для элементов массива, указанных с помощью отрицательных индексов, особенно неожиданно и, скорее всего, изменится.

Локализованное удаление элементов составных типов

Можно использовать конструкции delete local $array[$idx] и delete local $hash{key} для удаления записи составного типа для текущего блока и восстановления её при завершении блока. Они возвращают значение массива/хеша до локализации, что означает, что они соответственно эквивалентны

do {
    my $val = $array[$idx];
    local  $array[$idx];
    delete $array[$idx];
    $val
}

и

do {
    my $val = $hash{key};
    local  $hash{key};
    delete $hash{key};
    $val
}

за исключением того, что локализация local относится к блоку do. Также принимаются срезы.

my %hash = (
    a => [ 7, 8, 9 ],
    b => 1,
)

{
    my $x = delete local $hash{a};
    # $x is [ 7, 8, 9 ]
    # %hash is (b => 1)

    {
        my @nums = delete local @$x[0, 2]
        # @nums is (7, 9)
        # $x is [ undef, 8 ]

        $x[0] = 999; # will be erased when the scope ends
    }
    # $x is back to [ 7, 8, 9 ]

}
# %hash is back to its original state

Эта конструкция поддерживается с Perl v5.12.

Подпрограммы-lvalue

Можно вернуть изменяемое значение из подпрограммы. Для этого нужно объявить подпрограмму, возвращающую lvalue.

my $val;
sub canmod : lvalue {
    $val;  # or:  return $val;
}
sub nomod {
    $val;
}

canmod() = 5;   # assigns to $val
nomod()  = 5;   # ERROR

Скалярный/список контекст для подпрограммы и для правой части присваивания определяется так, как если бы вызов подпрограммы был заменён скаляром. Например, рассмотрим:

data(2,3) = get_data(3,4);

Обе подпрограммы здесь вызываются в скалярном контексте, а в:

(data(2,3)) = get_data(3,4);

и в:

(data(2),data(3)) = get_data(3,4);

все подпрограммы вызываются в контексте списка.

Подпрограммы-lvalue удобны, но нужно помнить, что при использовании с объектами они могут нарушать инкапсуляцию. Обычный мутатор может проверить переданный аргумент перед установкой защищаемого атрибута, а подпрограмма-lvalue не может. Если вам нужна какая-либо специальная обработка при сохранении и получении значений, рассмотрите использование модуля CPAN Sentinel или что-то подобное.

Лексические подпрограммы

Начиная с Perl 5.18, можно объявить закрытую подпрограмму с помощью my или state. Как и со статическими переменными, ключевое слово state доступно только в Perl use feature 'state' или use v5.10 и выше.

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

Эти подпрограммы видны только внутри блока, в котором они объявлены, и только после этого объявления:

# Include these two lines if your code is intended to run under Perl
# versions earlier than 5.26.
no warnings "experimental::lexical_subs";
use feature 'lexical_subs';

foo();              # calls the package/global subroutine
state sub foo {
    foo();          # also calls the package subroutine
}
foo();              # calls "state" sub
my $ref = \&foo;    # take a reference to "state" sub

my sub bar { ... }
bar();              # calls "my" sub

Нельзя (непосредственно) написать рекурсивную лексическую подпрограмму:

# WRONG
my sub baz {
    baz();
}

Этот пример терпит неудачу, потому что baz() относится к пакетной/глобальной подпрограмме baz, а не к лексической подпрограмме, которая в данный момент определяется.

Решение — использовать __SUB__:

my sub baz {
    __SUB__->();    # calls itself
}

Можно предварительно объявить лексическую подпрограмму. Синтаксис определения подпрограммы sub foo {...} учитывает любые предыдущие объявления my sub; или state sub;. Однако использование этого для определения рекурсивных подпрограмм — плохая идея:

my sub baz;         # predeclaration
sub baz {           # define the "my" sub
    baz();          # WRONG: calls itself, but leaks memory
}

Как и my $f; $f = sub { $f->() }, этот пример приводит к утечке памяти. Имя baz — ссылка на подпрограмму, и подпрограмма использует имя baz; они поддерживают друг друга в живых (см. "Circular References" в perlref).

state sub против my sub

В чём разница между подпрограммами «state» и «my»? Каждый раз, когда выполнение входит в блок с объявлением подпрограмм «my», создаётся новая копия каждой подпрограммы. Подпрограммы «state» сохраняются с одного выполнения содержащего блока на другой.

Таким образом, подпрограммы «state», как правило, быстрее. Но подпрограммы «my» необходимы, если нужно создать замыкания:

sub whatever {
    my $x = shift;
    my sub inner {
        ... do something with $x ...
    }
    inner();
}

В этом примере новый $x создаётся, когда вызывается whatever, и также создаётся новый inner, который может видеть новый $x. Подпрограмма «state» увидит только $x с первого вызова whatever.

our подпрограммы

Как и our $variable, our sub создаёт лексический псевдоним для пакетной подпрограммы с тем же именем.

Два основных использования этого — вернуться к пакетной подпрограмме внутри внутреннего раздела:

sub foo { ... }

sub bar {
    my sub foo { ... }
    {
        # need to use the outer foo here
        our sub foo;
        foo();
    }
}

и сделать подпрограмму видимой для других пакетов в том же разделе:

package MySneakyModule;

our sub do_something { ... }

sub do_something_with_caller {
    package DB;
    () = caller 1;          # sets @DB::args
    do_something(@args);    # uses MySneakyModule::do_something
}

Передача записей таблицы символов (typeglob)

ПРЕДУПРЕЖДЕНИЕ: Метод, описанный в этом разделе, первоначально был единственным способом имитировать передачу по ссылке в старых версиях Perl. Хотя он по-прежнему работает в современных версиях, новый механизм ссылок, как правило, проще в использовании. См. ниже.

Иногда вам нужно передать не значение массива в подпрограмму, а его имя, чтобы подпрограмма могла изменить глобальную копию, а не работать с локальной копией. В Perl можно сослаться на все объекты с определённым именем, добавив звёздочку перед именем: *foo. Это часто называют «typeglob», поскольку звёздочка в начале может рассматриваться как подстановочный символ для всех символов префиксов переменных, подпрограмм и т. д.

При оценке typeglob возвращается скалярное значение, представляющее все объекты с этим именем, включая файловый дескриптор, формат или подпрограмму. При присваивании это приводит к тому, что имя ссылается на значение *, которое ему присвоено. Пример:

sub doubleary {
    local(*someary) = @_;
    foreach $elem (@someary) {
        $elem *= 2;
    }
}
doubleary(*foo);
doubleary(*bar);

Скаляры уже передаются по ссылке, поэтому вы можете изменять скалярные аргументы без использования этого механизма, явно ссылаясь на $_[0] и т. д. Можно изменить все элементы массива, передавая все элементы как скаляры, но нужно использовать механизм * (или эквивалентный механизм ссылки) для push, pop или изменения размера массива. Определённо, передача typeglob (или ссылки) будет быстрее.

Даже если вам не нужно изменять массив, этот механизм полезен для передачи нескольких массивов в едином списке, поскольку обычно механизм списка объединяет все значения массива, так что вы не можете извлечь отдельные массивы. Более подробную информацию о typeglob см. в "Typeglobs and Filehandles" в perldata.

Когда всё ещё следует использовать local()

Несмотря на существование my, оператор local до сих пор пригождается в трёх случаях. На самом деле, в этих трёх случаях необходимо использовать local вместо my.

  1. Вам необходимо присвоить глобальной переменной временное значение, особенно переменной $_.

    Глобальные переменные, такие как @ARGV или переменные, представляющие знаки препинания, должны быть localзированы с помощью local(). Этот блок считывает /etc/motd и разбивает его на фрагменты, разделённые строками из знаков равенства, которые размещаются в @Fields.

    {
        local @ARGV = ("/etc/motd");
        local $/ = undef;
        local $_ = <>;
        @Fields = split /^\s*=+\s*$/;
    }

    В частности, важно localзировать $_ в любой процедуре, которая ей присваивает значение. Следите за неявными присваиваниями в while условных операторах.

  2. Вам нужно создать локальную обработку файла или каталога или локальную функцию.

    Функция, которой требуется собственная обработка файла, должна использовать local() на полном типеглобе. Это можно использовать для создания новых записей в таблице символов:

    sub ioqueue {
        local  (*READER, *WRITER);    # not my!
        pipe    (READER,  WRITER)     or die "pipe: $!";
        return (*READER, *WRITER);
    }
    ($head, $tail) = ioqueue();

    См. модуль Symbol, чтобы узнать, как создать анонимные записи в таблице символов.

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

    {
        local *grow = \&shrink; # only until this block exits
        grow();                # really calls shrink()
        move();                # if move() grow()s, it shrink()s too
    }
    grow();                    # get the real grow() again

    См. "Функциональные шаблоны" в perlref для получения дополнительной информации о манипулировании функциями по имени таким образом.

  3. Вы хотите временно изменить только один элемент массива или хеша.

    Вы можете localзировать только один элемент агрегата. Обычно это делается с динамическими данными:

    {
        local $SIG{INT} = 'IGNORE';
        funct();                            # uninterruptible
    }
    # interruptibility automatically restored here

    Но это также работает с лексически объявленными агрегатами.

Передача по ссылке

Если вы хотите передать в функцию более одного массива или хеша — или вернуть их из неё — и сохранить их целостность, то вам необходимо использовать явную передачу по ссылке. Прежде чем сделать это, вам необходимо понять ссылки, как описано в perlref. В противном случае этот раздел может показаться вам бессмысленным.

Вот несколько простых примеров. Сначала передадим несколько массивов в функцию и сделаем её pop все эти массивы, вернув новый список всех их предыдущих последних элементов:

@tailings = popmany ( \@w, \@x, \@y, \@z );

sub popmany {
    my $aref;
    my @retlist;
    foreach $aref ( @_ ) {
        push @retlist, pop @$aref;
    }
    return @retlist;
}

Вот как вы можете написать функцию, которая возвращает список ключей, встречающихся во всех хешах, переданных в неё:

@common = inter( \%foo, \%bar, \%joe );
sub inter {
    my ($k, $href, %seen); # locals
    foreach $href (@_) {
        while ( $k = each %$href ) {
            $seen{$k}++;
        }
    }
    return grep { $seen{$_} == @_ } keys %seen;
}

Пока мы используем только обычный механизм возврата списка. Что произойдёт, если вы хотите передать или вернуть хеш? Ну, если вы используете только один из них, или не против их конкатенации, то обычная схема вызова допустима, хотя и немного затратна.

Вот где люди сталкиваются с проблемами:

(@w, @x) = func(@y, @z);
or
(%w, %x) = func(%y, %z);

Этот синтаксис просто не сработает. Он задаёт только @w или %w и очищает @x или %x. Кроме того, функция не была передана в два отдельных массива или хеша: она получила один длинный список в @_, как всегда.

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

($wref, $xref) = func(\@y, \@z);
print "@$wref has more than @$xref\n";
sub func {
    my ($yref, $zref) = @_;
    if (@$yref > @$zref) {
        return ($yref, $zref);
    } else {
        return ($zref, $yref);
    }
}

Оказывается, вы можете сделать это и так:

(*w, *x) = func(\@y, \@z);
print "@w has more than @x\n";
sub func {
    local (*y, *z) = @_;
    if (@y > @z) {
        return (\@y, \@z);
    } else {
        return (\@z, \@y);
    }
}

Здесь мы используем типглобы для создания псевдонимов в таблице символов. Хотя это немного тонко, и это не сработает, если вы используете my переменные, поскольку только глобальные переменные (даже в виде local) находятся в таблице символов.

Если вы передаёте дескрипторы файлов, вы обычно можете использовать просто голое имя типглоба, как *STDOUT, но ссылки на типглобы тоже работают. Например:

splutter(\*STDOUT);
sub splutter {
    my $fh = shift;
    print $fh "her um well a hmmm\n";
}

$rec = get_rec(\*STDIN);
sub get_rec {
    my $fh = shift;
    return scalar <$fh>;
}

Если вы планируете создавать новые дескрипторы файлов, вы можете сделать это. Обратите внимание на то, что необходимо передать просто голое *FH, а не его ссылку.

sub openit {
    my $path = shift;
    local *FH;
    return open (FH, $path) ? *FH : undef;
}

Прототипы

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

sub mypush (\@@)
sub mypush :prototype(\@@)

тогда mypush() принимает аргументы точно так же, как push().

Если подпрограммы с сигнатурами включены (см. "Подпрограммы с сигнатурами"), то более короткий синтаксис PROTO недоступен, поскольку он конфликтует с сигнатурами. В этом случае прототип может быть объявлен только в виде атрибута.

Объявление функции должно быть видно во время компиляции. Прототип влияет только на интерпретацию вызовов функции нового стиля, где «новый стиль» определён как отсутствие использования символа &. Другими словами, если вы вызываете её как встроенную функцию, она будет вести себя как встроенная функция. Если вы вызываете её как старую подпрограмму, она будет вести себя как старая подпрограмма. Естественным следствием этого правила является то, что прототипы не влияют на ссылки на подпрограммы, такие как \&foo или на косвенные вызовы подпрограмм, такие как &{$subref} или $subref->().

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

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

Declared as             Called as

sub mylink ($$)         mylink $old, $new
sub myvec ($$$)         myvec $var, $offset, 1
sub myindex ($$;$)      myindex &getstring, "substr"
sub mysyswrite ($$$;$)  mysyswrite $buf, 0, length($buf) - $off, $off
sub myreverse (@)       myreverse $x, $y, $z
sub myjoin ($@)         myjoin ":", $x, $y, $z
sub mypop (\@)          mypop @array
sub mysplice (\@$$@)    mysplice @array, 0, 2, @pushme
sub mykeys (\[%@])      mykeys $hashref->%*
sub myopen (*;$)        myopen HANDLE, $name
sub mypipe (**)         mypipe READHANDLE, WRITEHANDLE
sub mygrep (&@)         mygrep { /foo/ } $x, $y, $z
sub myrand (;$)         myrand 42
sub mytime ()           mytime

Любой обрамлённый обратной косой чертой символ прототипа представляет собой фактический аргумент, который должен начинаться с этого символа (при необходимости, предваряемый my, our или local). за исключением $, который примет любое скалярное выражение lvalue, например, $foo = 7 или my_function()->[0]. Значение, переданное как часть @_, будет ссылкой на фактический аргумент, предоставленный в вызове подпрограммы, полученный путём применения \ к этому аргументу.

Вы можете использовать обозначение группы обратной косой черты \[] для указания более чем одного допустимого типа аргумента. Например:

sub myref (\[$@%&*])

разрешит вызов myref() в виде

myref $var
myref @array
myref %hash
myref &sub
myref *glob

и первым аргументом myref() будет ссылка на скаляр, массив, хеш, код или типглоб.

Символы прототипа без обратной косой черты имеют специальное значение. Любой необрамлённый @ или % съедает все оставшиеся аргументы и принудительно устанавливает контекст списка. Аргумент, представленный $, принудительно устанавливает скалярный контекст. & требует анонимной подпрограммы, которая, если передаётся в качестве первого аргумента, не требует ключевого слова sub или последующей запятой.

* позволяет подпрограмме принимать ключевое слово, константу, скалярное выражение, типглоб или ссылку на типглоб в этом месте. Значение будет доступно подпрограмме либо как простой скаляр, либо (в двух последних случаях) как ссылка на типглоб. Если вы хотите всегда преобразовывать такие аргументы в ссылку на типглоб, используйте Symbol::qualify_to_ref() следующим образом:

use Symbol 'qualify_to_ref';

sub foo (*) {
    my $fh = qualify_to_ref(shift, caller);
    ...
}

Прототип + — это специальная альтернатива $, которая будет работать как \[@%], когда ей передаётся буквальный массив или хеш, но в противном случае принудительно устанавливает скалярный контекст для аргумента. Это полезно для функций, которые должны принимать либо буквальный массив, либо ссылку на массив в качестве аргумента:

sub mypush (+@) {
    my $aref = shift;
    die "Not an array or arrayref" unless ref $aref eq 'ARRAY';
    push @$aref, @_;
}

При использовании прототипа + ваша функция должна проверять, что аргумент является допустимого типа.

Точка с запятой (;) отделяет обязательные аргументы от необязательных. Она избыточна перед @ или %, которые поглощают всё остальное.

В качестве последнего символа прототипа или непосредственно перед точкой с запятой символ @ или %, вы можете использовать _ вместо $: если этот аргумент не предоставлен, $_ будет использоваться вместо него.

Обратите внимание, как три последних примера в таблице выше обрабатываются парсером особым образом. mygrep() парсится как настоящий оператор списка, myrand() парсится как настоящий унарный оператор с унарным приоритетом, таким же, как rand(), а mytime() действительно не имеет аргументов, как и time(). То есть, если вы скажете

mytime +2;

получите mytime() + 2, а не mytime(2), как это было бы при парсинге без прототипа. Если вы хотите принудительно установить унарную функцию в том же приоритете, что и оператор списка, добавьте ; в конец прототипа:

sub mygetprotobynumber($;);
mygetprotobynumber $x > $y; # parsed as mygetprotobynumber($x > $y)

Интересно, что с помощью & можно сгенерировать новый синтаксис, при условии, что он находится в начальной позиции:

sub try (&@) {
    my($try,$catch) = @_;
    eval { &$try };
    if ($@) {
        local $_ = $@;
        &$catch;
    }
}
sub catch (&) { $_[0] }

try {
    die "phooey";
} catch {
    /phooey/ and print "unphooey\n";
};

Это выводит "unphooey". (Да, всё ещё остаются нерешённые вопросы, связанные с видимостью @_. Я пока отложу этот вопрос. (Но обратите внимание, что если мы сделаем @_ лексически охватывающим, эти анонимные подпрограммы могут действовать как замыкания... (Ой, это звучит немного по-лисповски? (Забудьте об этом.) )).

И вот повторная реализация оператора Perl grep:

sub mygrep (&@) {
    my $code = shift;
    my @result;
    foreach $_ (@_) {
        push(@result, $_) if &$code;
    }
    @result;
}

Некоторые люди предпочитали бы полноценные буквенно-цифровые прототипы. Буквенно-цифровые прототипы намеренно исключены из прототипов для того, чтобы в будущем можно было добавить именованные формальные параметры. Основная цель текущего механизма — предоставить авторам модулей лучшие средства диагностики для пользователей модуля. Ларри считает обозначение достаточно понятным для программистов Perl и что оно не будет существенно мешать основному содержанию модуля и не сделает его труднее читать. Шумовое воздействие визуально заключено в небольшой капсуле, которую легко проглотить.

Если вы попытаетесь использовать буквенно-цифровую последовательность в прототипе, это сгенерирует необязательное предупреждение — «Недопустимый символ в прототипе…». К сожалению, в более ранних версиях Perl прототип можно было использовать, если его префикс был допустимым прототипом. Предупреждение может быть изменено на ошибку в будущей версии Perl, после того, как большая часть проблемного кода будет исправлена.

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

sub func ($) {
    my $n = shift;
    print "you gave me $n\n";
}

а кто-то её вызывал с массивом или выражением, возвращающим список:

func(@foo);
func( $text =~ /\w+/g );

Тогда вы просто предоставили автоматическую scalar перед их аргументом, что может быть весьма неожиданно. Старый @foo, который раньше хранил одну вещь, не передаётся. Вместо этого func() теперь передаётся в виде 1; то есть, количество элементов в @foo. А функция m//g вызывается в скалярном контексте, поэтому вместо списка слов она возвращает булево значение и перемещает pos($text). Ой!

Если у подпрограммы есть и PROTO, и BLOCK, прототип не применяется до тех пор, пока BLOCK не будет полностью определён. Это означает, что рекурсивной функции с прототипом необходимо предварительное объявление, чтобы прототип вступил в силу, как это показано ниже:

sub foo($$);
sub foo($$) {
    foo 1, 2;
}

Конечно, всё это очень мощно и должно использоваться только умеренно, чтобы сделать мир лучше.

Постоянные функции

Функции с прототипом () — потенциальные кандидаты для встраивания. Если результат после оптимизации и свёртки констант — константа или лексически-ограниченный скаляр, у которого нет других ссылок, то он будет использован вместо вызова функции, сделанного без &. Вызовы, сделанные с помощью &, никогда не встраиваются. (См. constant для простого способа объявления большинства констант.)

Следующие функции будут встроены:

sub pi ()           { 3.14159 }             # Not exact, but close.
sub PI ()           { 4 * atan2 1, 1 }      # As good as it gets,
                                            # and it's inlined, too!
sub ST_DEV ()       { 0 }
sub ST_INO ()       { 1 }

sub FLAG_FOO ()     { 1 << 8 }
sub FLAG_BAR ()     { 1 << 9 }
sub FLAG_MASK ()    { FLAG_FOO | FLAG_BAR }

sub OPT_BAZ ()      { not (0x1B58 & FLAG_MASK) }

sub N () { int(OPT_BAZ) / 3 }

sub FOO_SET () { 1 if FLAG_MASK & FLAG_FOO }
sub FOO_SET2 () { if (FLAG_MASK & FLAG_FOO) { 1 } }

(Обратите внимание, что в последнем примере встраивание не всегда происходило в Perl 5.20 и более ранних версиях, которые не вели себя последовательно с подпрограммами, содержащими внутренние области видимости.) Вы можете запретить встраивание, используя явное return:

sub baz_val () {
    if (OPT_BAZ) {
        return 23;
    }
    else {
        return 42;
    }
}
sub bonk_val () { return 12345 }

Как уже упоминалось ранее, вы также можете динамически объявлять встраиваемые подпрограммы во время выполнения BEGIN, если их тело состоит из лексически-ограниченного скаляра, у которого нет других ссылок. Только первый пример здесь будет встроен:

BEGIN {
    my $var = 1;
    no strict 'refs';
    *INLINED = sub () { $var };
}

BEGIN {
    my $var = 1;
    my $ref = \$var;
    no strict 'refs';
    *NOT_INLINED = sub () { $var };
}

Неочевидный нюанс с этим (см. [RT #79908]) — что произойдёт, если переменная потенциально может быть изменяемой. Например:

BEGIN {
    my $x = 10;
    *FOO = sub () { $x };
    $x++;
}
print FOO(); # printed 10 prior to 5.32.0

Начиная с Perl 5.22, это вызвало предупреждение о устаревании, а начиная с Perl 5.32 — ошибку выполнения. Раньше переменная немедленно встраивалась и переставала вести себя как обычная лексическая переменная; поэтому выводилось 10, а не 11.

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

# Fine, no warning
BEGIN {
    my $x = 54321;
    *INLINED = sub () { $x };
}
# Error
BEGIN {
    my $x;
    $x = 54321;
    *ALSO_INLINED = sub () { $x };
}

Perl 5.22 также вводит экспериментальный атрибут «const» в качестве альтернативы. (Отключите предупреждения «experimental::const_attr», если хотите его использовать.) При применении к анонимной подпрограмме, она заставляет подпрограмму вызываться при оценке выражения sub. Возвращаемое значение сохраняется и преобразуется в константную подпрограмму:

my $x = 54321;
*INLINED = sub : const { $x };
$x++;

Возвращаемое значение INLINED в этом примере всегда будет 54321, независимо от последующих изменений $x. Вы также можете поместить любой произвольный код внутри подпрограммы, и он будет выполнен немедленно, а его возвращаемое значение будет сохранено аналогичным образом.

Если вам действительно нужна подпрограмма с прототипом () , которая возвращает лексическую переменную, вы можете легко заблокировать её встраивание, добавив явное return:

BEGIN {
    my $x = 10;
    *FOO = sub () { return $x };
    $x++;
}
print FOO(); # prints 11

Наиболее простой способ определить, была ли встроена подпрограмма, — использовать B::Deparse. Рассмотрим этот пример двух подпрограмм, возвращающих 1, одна с прототипом (), вызывающим встраивание, а другая без него (вывод deparse усечен для наглядности):

$ perl -MO=Deparse -e 'sub ONE { 1 } if (ONE) { print ONE if ONE }'
sub ONE {
    1;
}
if (ONE ) {
    print ONE() if ONE ;
}

$ perl -MO=Deparse -e 'sub ONE () { 1 } if (ONE) { print ONE if ONE }'
sub ONE () { 1 }
do {
    print 1
};

Если вы переопределяете подпрограмму, которая могла быть встроена, по умолчанию вы получите предупреждение. Вы можете использовать это предупреждение, чтобы определить, является ли конкретная подпрограмма встраиваемой, поскольку оно отличается от предупреждения о перезаписи невстраиваемых подпрограмм:

$ perl -e 'sub one () {1} sub one () {2}'
Constant subroutine one redefined at -e line 1.
$ perl -we 'sub one {1} sub one {2}'
Subroutine one redefined at -e line 1.

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

sub not_inlined () { return 23 }

Переопределение встроенных функций

Многие встроенные функции могут быть переопределены, хотя это следует делать только в исключительных случаях и по уважительной причине. Как правило, это может быть сделано пакетом, пытающимся эмулировать отсутствующую встроенную функциональность на не-Unix-системе.

Переопределение может быть выполнено только путём импорта имени из модуля во время компиляции — обычного предопределения недостаточно. Однако, pragma use subs позволяет, по сути, предопределять подпрограммы с помощью синтаксиса импорта, и эти имена могут затем переопределять встроенные:

use subs 'chdir', 'chroot', 'chmod', 'chown';
chdir $somewhere;
sub chdir { ... }

Для однозначной ссылки на встроенную форму используйте специальный квалификатор пакета CORE::. Например, CORE::open() всегда ссылается на встроенную open(), даже если текущий пакет импортировал другую подпрограмму с именем &open() из другого места. Несмотря на то, что это выглядит как обычный вызов функции, это не так: префикс CORE:: в этом случае является частью синтаксиса Perl и работает для любого ключевого слова, независимо от того, что содержится в пакете CORE. Получение ссылки на него, то есть \&CORE::open, работает только для некоторых ключевых слов. См. CORE.

Модули библиотек в общем случае не должны экспортировать встроенные имена, такие как open или chdir, в качестве части их стандартного списка экспорта @EXPORT, потому что они могут незаметно попасть в пространство имён другого человека и изменить семантику неожиданным образом. Вместо этого, если модуль добавляет это имя в @EXPORT_OK, то пользователь может явно импортировать имя, но не неявно. То есть, они могут сказать

use Module 'open';

и это импортирует переопределение open. Но если они скажут

use Module;

они получат стандартные импорты без переопределений.

Представленный выше механизм переопределения встроенных функций ограничен, намеренно, пакетом, который запрашивает импорт. Существует второй метод, который иногда применим, когда вы хотите переопределить встроенную функцию везде, не обращая внимания на границы пространств имён. Это достигается путём импорта подпрограммы в специальное пространство имён CORE::GLOBAL::. Вот пример, который довольно смело заменяет оператор glob чем-то, что понимает регулярные выражения.

package REGlob;
require Exporter;
@ISA = 'Exporter';
@EXPORT_OK = 'glob';

sub import {
    my $pkg = shift;
    return unless @_;
    my $sym = shift;
    my $where = ($sym =~ s/^GLOBAL_// ? 'CORE::GLOBAL' : caller(0));
    $pkg->export($where, $sym, @_);
}

sub glob {
    my $pat = shift;
    my @got;
    if (opendir my $d, '.') {
        @got = grep /$pat/, readdir $d;
        closedir $d;
    }
    return @got;
}
1;

А вот как это можно (злоупотребляя) использовать:

#use REGlob 'GLOBAL_glob';      # override glob() in ALL namespaces
package Foo;
use REGlob 'glob';              # override glob() in Foo:: only
print for <^[a-z_]+\.pm\$>;     # show all pragmatic modules

Исходный комментарий демонстрирует искусственный, даже опасный пример. Переопределяя glob глобально, вы вынудите новое (и деструктивное) поведение оператора glob для каждого пространства имён без полного знания или сотрудничества модулей, владеющих этими пространствами имён. Естественно, это должно выполняться с крайней осторожностью — если это вообще необходимо.

Приведённый выше пример REGlob не реализует всей необходимой поддержки для чистого переопределения Perl-оператора glob. Встроенный оператор glob имеет различное поведение в зависимости от того, появляется ли он в скалярном или списковом контексте, но наш оператор REGlob нет. Действительно, многие встроенные функции Perl обладают такой контекстно-зависимой семантикой, и эти функции должны быть надлежащим образом поддержаны должным образом написанным переопределением. Для полностью функционального примера переопределения оператора glob изучите реализацию File::DosGlob в стандартной библиотеке.

При переопределении встроенной функции ваше замещение должно быть согласованным (если это возможно) с исходным синтаксисом встроенной функции. Вы можете достичь этого, используя подходящий прототип. Чтобы получить прототип переопределяемой встроенной функции, используйте функцию prototype с аргументом "CORE::builtin_name" (см. "prototype" в perlfunc).

Однако, следует учитывать, что некоторые встроенные функции не могут иметь свой синтаксис, выраженный через прототип (такие как system или chomp). Если вы их переопределите, вы не сможете полностью воспроизвести их исходный синтаксис.

Встроенные функции do, require и glob также могут быть переопределены, но благодаря специальной магии их исходный синтаксис сохраняется, и вам не нужно определять прототип для их заменителей. (Вы не можете переопределить синтаксис do BLOCK).

require имеет особую дополнительную магию: если вы вызовете ваше переопределение require как require Foo::Bar, он фактически получит аргумент "Foo/Bar.pm" в @_. См. "require" в perlfunc.

И, как вы, возможно, заметили из предыдущего примера, если вы переопределите glob, оператор глобального подбора <*> также переопределяется.

Аналогичным образом, переопределение функции readline также переопределяет эквивалентный оператор ввода-вывода <FILEHANDLE>. Также, переопределение readpipe переопределяет операторы `` и qx//.

Наконец, некоторые встроенные функции (например, exists или grep ) не могут быть переопределены.

Автозагрузка

Если вы вызываете неопределённую подпрограмму, вы, как правило, получите немедленную ошибку, жалуясь на то, что подпрограмма не существует. (Аналогично для подпрограмм, используемых как методы, когда метод не существует ни в одном базовом классе пакета класса.) Однако, если подпрограмма AUTOLOAD определена в пакете или пакетах, используемых для поиска исходной подпрограммы, то эта подпрограмма AUTOLOAD вызывается с аргументами, которые были бы переданы исходной подпрограмме. Полностью квалифицированное имя исходной подпрограммы магическим образом появляется в глобальной переменной $AUTOLOAD того же пакета, что и подпрограмма AUTOLOAD. Имя не передаётся как обычный аргумент, потому что, эмм, ну, просто так. (В качестве исключения, вызов метода несуществующего метода import или unimport просто пропускается. Кроме того, если подпрограмма AUTOLOAD — XSUB, существуют и другие способы получения имени подпрограммы. См. "Автозагрузка с XSUB" в perlguts для получения дополнительной информации.)

Многие подпрограммы AUTOLOAD загружают определение необходимой подпрограммы с помощью eval(), а затем выполняют эту подпрограмму с помощью специальной формы goto(), которая стирает кадр стека подпрограммы AUTOLOAD без следа. (См. исходный код стандартного модуля, описанного в AutoLoader, например.) Но подпрограмма AUTOLOAD также может просто эмулировать подпрограмму и никогда не определять её. Например, предположим, что функция, которая не была определена, должна просто вызвать system с этими аргументами. Всё, что вам нужно сделать:

sub AUTOLOAD {
    our $AUTOLOAD;              # keep 'use strict' happy
    my $program = $AUTOLOAD;
    $program =~ s/.*:://;
    system($program, @_);
}
date();
who();
ls('-l');

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

use subs qw(date who ls);
date;
who;
ls '-l';

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

Доступны механизмы, помогающие авторам модулей разбивать их модули на загружаемые файлы. См. стандартный модуль AutoLoader, описанный в AutoLoader и в AutoSplit, стандартные модули SelfLoader в SelfLoader и документ о добавлении функций C в код Perl в perlxs.

Атрибуты подпрограмм

Объявление или определение подпрограммы может иметь список связанных с ней атрибутов. Если такой список атрибутов присутствует, он разбивается на границах пробелов или двоеточий и обрабатывается так, как будто было видно use attributes . См. attributes для получения дополнительной информации о поддерживаемых в настоящее время атрибутах. В отличие от ограничения с устаревшем use attrs, синтаксис sub : ATTRLIST позволяет ассоциировать атрибуты с предварительным объявлением, а не только с определением подпрограммы.

Атрибуты должны быть допустимыми именами простых идентификаторов (без каких-либо знаков препинания, кроме символа «_»). Они могут иметь список параметров, который проверяется только на корректное вложение скобок «(», «)».

Примеры корректного синтаксиса (хотя атрибуты неизвестны):

sub fnord (&\%) : switch(10,foo(7,3))  :  expensive;
sub plugh () : Ugly('\(") :Bad;
sub xyzzy : _5x5 { ... }

Примеры некорректного синтаксиса:

sub fnord : switch(10,foo();    # ()-string not balanced
sub snoid : Ugly('(');          # ()-string not balanced
sub xyzzy : 5x5;                # "5x5" not a valid identifier
sub plugh : Y2::north;          # "Y2::north" not a simple identifier
sub snurt : foo + bar;          # "+" not a colon or space

Список атрибутов передаётся в виде списка константных строк в код, который ассоциирует их с подпрограммой. В частности, второй пример корректного синтаксиса выше в настоящее время выглядит следующим образом с точки зрения его разбора и вызова:

use attributes __PACKAGE__, \&plugh, q[Ugly('\(")], 'Bad';

Дополнительную информацию о списках атрибутов и их обработке см. в attributes и Attribute::Handlers.

ДРУГОЕ

См. "Шаблоны функций" в perlref для получения дополнительной информации о ссылках и замыканиях. См. perlxs, если вы хотите узнать о вызове C-подпрограмм из Perl. См. perlembed, если вы хотите узнать о вызове Perl-подпрограмм из C. См. perlmod, чтобы узнать о группировании функций в отдельных файлах. См. perlmodlib, чтобы узнать, какие стандартные модули библиотек доступны на вашей системе. См. perlootut, чтобы узнать, как делать вызовы методов объекта.

© 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/perlsub

Spec-Zone.ru

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