Spec-Zone.ru › Perl 5.38

атрибуты

СОДЕРЖАНИЕ

  • ИМЯ
  • СИНОПСИС
  • ОПИСАНИЕ
    • Что делает 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" в качестве своего 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 получит все вышеуказанные экспорты.

ПРИМЕРЫ

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

  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–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/attributes

Spec-Zone.ru

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