Spec-Zone.ru › Perl 5.30

Атрибуты

СОДЕРЖАНИЕ

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

ИМЯ

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» в качестве своего type, и даже благословленная ссылка на хэш-массив использует «HASH» в качестве своего type.

Вызываемые методы класса для изменения и получения следующие:

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–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.30.3/attributes

Spec-Zone.ru

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