Spec-Zone.ru › Perl 5.34

Атрибуты

СОДЕРЖАНИЕ

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

ИМЯ

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(). (См. "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 получит все вышеуказанные экспорты.

ПРИМЕРЫ

Ниже приведены некоторые примеры синтаксически правильных объявлений с аннотациями о том, как они интерпретируются 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').

См. также

"Переменные без доступа извне via 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.34.0/attributes

Spec-Zone.ru

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