Spec-Zone.ru › Perl 5.32

атрибуты

СОДЕРЖАНИЕ

  • ИМЯ
  • СИНТАКСИС
  • ОПИСАНИЕ
    • Что делает импорт
    • Встроенные атрибуты
    • Доступные подпрограммы
    • Обработка атрибутов, специфичных для пакета
    • Синтаксис списков атрибутов
  • ЭКСПОРТ
    • По умолчанию экспортируются
    • Доступные экспортные данные
    • Определенные экспортные теги
  • ПРИМЕРЫ
  • ДОПОЛНИТЕЛЬНЫЕ ПРИМЕРЫ
  • СМОТРИТЕ ТАКЖЕ

ИМЯ

attributes - получение/установка атрибутов подпрограммы или переменной

СИНТАКСИС

sub foo : method ;
my ($x,@y,%z) : Bent = 1;
my $s = sub : method { ... };

use attributes ();    # optional, to get subroutine declarations
my @attrlist = attributes::get(\&foo);

use attributes 'get'; # import the attributes::get subroutine
my @attrlist = get \&foo;

ОПИСАНИЕ

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

use attributes __PACKAGE__, \&foo, 'method';

Второй пример в синтаксисе делает нечто эквивалентное этому:

use attributes ();
my ($x,@y,%z);
attributes::->import(__PACKAGE__, \$x, 'Bent');
attributes::->import(__PACKAGE__, \@y, 'Bent');
attributes::->import(__PACKAGE__, \%z, 'Bent');
($x,@y,%z) = 1;

Да, это довольно много расширений.

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

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

Установка атрибутов подпрограммы происходит во время компиляции. Атрибуты переменных в our декларациях также применяются во время компиляции. Однако для my переменных атрибуты применяются во время выполнения. Это означает, что вам необходимо обратиться к компоненту времени выполнения my, прежде чем эти атрибуты будут применены. Например:

my $x : Bent = 42 if 0;

не присвоит 42 переменной $x, ни не применит атрибут Bent к переменной.

Попытка установить неизвестный атрибут — это фатальная ошибка. (Ошибка может быть перехвачена, но она всё равно останавливает компиляцию в рамках eval.) Установка атрибута с именем, состоящим только из строчных букв, который не является встроенным атрибутом (например, «foo»), приведёт к предупреждению с помощью -w или use warnings 'reserved'.

Что import делает

В описании упоминается, что

sub foo : method;

эквивалентно

use attributes __PACKAGE__, \&foo, 'method';

Как вы, возможно, знаете, это вызывает функцию import модуля attributes во время компиляции с этими параметрами: «attributes», имя пакета вызывающего модуля, ссылка на код и «method».

attributes->import( __PACKAGE__, \&foo, 'method' );

Итак, вы хотите узнать, что import фактически делает?

Прежде всего, import получает тип третьего параметра («CODE» в данном случае). attributes.pm проверяет, существует ли подпрограмма под названием MODIFY_<reftype>_ATTRIBUTES в пространстве имён вызывающего модуля (здесь: «main»). В этом случае требуется подпрограмма MODIFY_CODE_ATTRIBUTES. Затем эта подпрограмма вызывается для проверки, не использовали ли вы «плохой атрибут». Вызов подпрограммы в этом примере будет выглядеть следующим образом:

MODIFY_CODE_ATTRIBUTES( 'main', \&foo, 'method' );

MODIFY_<reftype>_ATTRIBUTES должна вернуть список всех «плохих атрибутов». Если есть какие-либо плохие атрибуты, import генерирует ошибку.

(См. Обработка атрибутов, специфичных для пакета ниже.)

Встроенные атрибуты

Ниже приведены встроенные атрибуты для подпрограмм:

lvalue

Указывает, что ссылка на подпрограмму является допустимым lvalue и может быть присвоена. Подпрограмма должна возвращать изменяемое значение, такое как скалярная переменная, как описано в perlsub.

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

method

Указывает, что ссылка на подпрограмму является методом. Подпрограмма, помеченная таким образом, не будет вызывать предупреждение «Неоднозначный вызов разрешён как CORE::%s».

prototype(..)

Атрибут «prototype» — это альтернативный способ указания прототипа подпрограммы. Желаемый прототип находится в скобках.

Прототип из атрибута присваивается подпрограмме сразу после прототипа из подпрограммы, что означает, что если оба объявлены одновременно, традиционно определённый прототип игнорируется. Другими словами, sub foo($$) : prototype(@) {} неотличим от sub foo(@){}.

Если включены предупреждения illegalproto, прототип, объявленный в этом атрибуте, будет проверен на корректность во время компиляции.

const

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

Ниже приведены встроенные атрибуты для переменных:

shared

Указывает, что переменная может быть общей для различных потоков при использовании совместно с модулями threads и threads::shared.

Доступные подпрограммы

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

get

Эта подпрограмма ожидает один параметр — ссылку на подпрограмму или переменную. Она возвращает список атрибутов, который может быть пустым. При передаче недопустимых аргументов используется die() (через Carp::croak) для поднятия фатальной ошибки. Если она может найти подходящее имя пакета для поиска класса метода, она включит результаты вызова FETCH_type_ATTRIBUTES в свой список возвращаемых значений, как описано в Обработке атрибутов, специфичных для пакета ниже. В противном случае будут возвращены только встроенные атрибуты.

reftype

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

Обратите внимание, что эти подпрограммы не экспортируются по умолчанию.

Обработка атрибутов, специфичных для пакета

ПРЕДУПРЕЖДЕНИЕ: механизмы, описанные здесь, всё ещё находятся на стадии эксперимента. Не полагайтесь на текущую реализацию. В частности, нет способа применения атрибутов пакета к «клонированным» копиям подпрограмм, используемых в качестве замыканий. (См. "Создание ссылок" в perlref для получения информации о замыканиях.) Обработка атрибутов, специфичных для пакета, может измениться несовместимым образом в будущей версии.

Когда в декларации присутствует список атрибутов, выполняется проверка наличия обработчика атрибутов «modify» в соответствующем пакете (или в его дереве наследования @ISA). Аналогично, когда вызывается attributes::get для действительной ссылки, выполняется проверка наличия соответствующего обработчика атрибутов «fetch». См. ПРИМЕРЫ, чтобы увидеть, как работает определение «соответствующего пакета».

Имена обработчиков основаны на базовом типе объявляемой переменной или ссылки, переданной. Поскольку эти атрибуты связаны с декларациями подпрограмм или переменных, это намеренно игнорирует любую возможность благословения в какой-либо пакет. Таким образом, декларация подпрограммы использует «CODE» в качестве своего типа, и даже ссылка на благословенный хеш использует «HASH» в качестве своего типа.

Вызываемые методы класса для модификации и извлечения:

FETCH_type_ATTRIBUTES

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

MODIFY_type_ATTRIBUTES

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

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

Вызов attributes::get() из области декларации пакета со значением NULL package ; для ссылки на неблагословлённую переменную не предоставит начального имени пакета для поиска метода «fetch». Таким образом, в этой ситуации вызов метода для атрибутов, определённых в пакете, не произойдёт. Именованная подпрограмма знает, к какой записи таблицы символов она принадлежит (или изначально принадлежала), и она будет использовать соответствующий пакет. Анонимная подпрограмма знает имя пакета, в который она была скомпилирована (если только она не была скомпилирована с декларацией пакета со значением NULL), и поэтому она будет использовать это имя пакета.

Синтаксис списков атрибутов

Список атрибутов представляет собой последовательность спецификаций атрибутов, разделённых пробелами или двоеточием (с необязательными пробелами). Каждая спецификация атрибута — это простое имя, за которым необязательно следует список параметров в скобках. Если такой список параметров присутствует, он сканируется в соответствии с правилами оператора q(). (См. "Quote and Quote-like Operators" в perlop.) Список параметров передаётся так, как он был найден, а не в соответствии с q().

Примеры синтаксически корректных списков атрибутов:

switch(10,foo(7,3))  :  expensive
Ugly('\(") :Bad
_5x5
lvalue method

Примеры синтаксически некорректных списков атрибутов (с аннотацией):

switch(10,foo()             # ()-string not balanced
Ugly('(')                   # ()-string not balanced
5x5                         # "5x5" not a valid identifier
Y2::north                   # "Y2::north" not a simple identifier
foo + bar                   # "+" neither a colon nor whitespace

ЭКСПОРТИРУЕМЫЕ ЭЛЕМЕНТЫ

Значения по умолчанию

Нет.

Доступные экспорты

Процедуры get и reftype экспортируемы.

Определённые теги экспорта

Тег :ALL получит все вышеперечисленные экспорты.

ПРИМЕРЫ

Ниже приведены примеры синтаксически корректных объявлений, с аннотацией того, как они интерпретируются в вызовы use attributes в perl. Эти примеры в основном полезны для демонстрации того, как для возможного поиска методов для атрибутов, определённых в пакете, находится «подходящий пакет».

  1. Код:

    package Canine;
    package Dog;
    my Canine $spot : Watchful ;

    Результат:

    use attributes ();
    attributes::->import(Canine => \$spot, "Watchful");
  2. Код:

    package Felis;
    my $cat : Nervous;

    Результат:

    use attributes ();
    attributes::->import(Felis => \$cat, "Nervous");
  3. Код:

    package X;
    sub foo : lvalue ;

    Результат:

    use attributes X => \&foo, "lvalue";
  4. Код:

    package X;
    sub Y::x : lvalue { 1 }

    Результат:

    use attributes Y => \&Y::x, "lvalue";
  5. Код:

    package X;
    sub foo { 1 }
    
    package Y;
    BEGIN { *bar = \&X::foo; }
    
    package Z;
    sub Y::bar : lvalue ;

    Результат:

    use attributes X => \&X::foo, "lvalue";

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

ДОПОЛНИТЕЛЬНЫЕ ПРИМЕРЫ

  1. sub MODIFY_CODE_ATTRIBUTES {
       my ($class,$code,@attrs) = @_;
    
       my $allowed = 'MyAttribute';
       my @bad = grep { $_ ne $allowed } @attrs;
    
       return @bad;
    }
    
    sub foo : MyAttribute {
       print "foo\n";
    }

    Этот пример выполняется. Во время компиляции вызывается MODIFY_CODE_ATTRIBUTES. В этой подпрограмме проверяется, запрещены ли какие-либо атрибуты, и возвращается список этих «плохих атрибутов».

    Поскольку возвращается пустой список, всё в порядке.

  2. sub MODIFY_CODE_ATTRIBUTES {
       my ($class,$code,@attrs) = @_;
    
       my $allowed = 'MyAttribute';
       my @bad = grep{ $_ ne $allowed }@attrs;
    
       return @bad;
    }
    
    sub foo : MyAttribute Test {
       print "foo\n";
    }

    Этот пример прерывается во время компиляции, поскольку используется атрибут «Test», который запрещён. MODIFY_CODE_ATTRIBUTES возвращает список, содержащий единственный элемент ('Test').

См. также

"Переменные с ограниченным доступом с помощью my()" в perlsub и "Атрибуты подпрограмм" в perlsub для получения подробностей об основных объявлениях; "use" в perlfunc для получения подробностей о механизме обычного вызова.

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.32.0/attributes

Spec-Zone.ru

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