Spec-Zone.ru › Perl 5.36

атрибуты

СОДЕРЖАНИЕ

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

ИМЯ

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() из области объявления пустого пакета package ; для ссылки на не освященную переменную не предоставит имя начального пакета для поиска метода 'fetch'. Таким образом, в этом случае метод вызова для атрибутов, определённых в пакете, не будет выполнен. Имя подпрограммы знает, к какой записи таблицы символов она принадлежит (или изначально принадлежала), и она будет использовать соответствующий пакет. Анонимная подпрограмма знает имя пакета, в который она была скомпилирована (если она также не была скомпилирована с объявлением пустого пакета), и поэтому она будет использовать это имя пакета.

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

Список атрибутов — это последовательность спецификаций атрибутов, разделенных пробелами или двоеточием (с необязательными пробелами). Каждая спецификация атрибута — это простое имя, за которым необязательно следует список параметров в скобках. Если такой список параметров присутствует, он сканируется с учетом правил для оператора q(). (См. "Операторы кавычек и похожие на кавычки" в 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–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/attributes

Spec-Zone.ru

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