атрибуты
СОДЕРЖАНИЕ
НАЗВАНИЕ
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выражение вычисляется. Возвращаемое значение сохраняется и превращается в константную подпрограмму.
Ниже приведены встроенные атрибуты для переменных:
-
Указывает, что указанная переменная может быть разделена между различными потоками при использовании совместно с модулями threads и threads::shared.
Доступные подпрограммы
После загрузки этого модуля доступны следующие подпрограммы общего назначения:
- get
-
Эта подпрограмма ожидает один параметр — ссылку на подпрограмму или переменную. Она возвращает список атрибутов, который может быть пустым. При передаче недопустимых аргументов используется die() (через Carp::croak) для создания фатальной ошибки. Если она может найти соответствующее имя пакета для поиска метода класса, она включит результаты вызова
FETCH_type_ATTRIBUTESв свой список возвращаемых значений, как описано в Обработке атрибутов, специфичных для пакета ниже. В противном случае будут возвращены только встроенные атрибуты. - reftype
-
Эта подпрограмма ожидает один параметр — ссылку на подпрограмму или переменную. Она возвращает встроенный тип ссылаемой переменной, игнорируя любой пакет, в который она могла быть освящена. Это может быть полезно для определения значения типа, которое является частью имён методов, описанных в Обработке атрибутов, специфичных для пакета ниже.
Обратите внимание, что эти подпрограммы не экспортируются по умолчанию.
Обработка атрибутов, специфичных для пакета
ПРЕДУПРЕЖДЕНИЕ: механизмы, описанные здесь, всё ещё находятся в стадии эксперимента. Не полагайтесь на текущую реализацию. В частности, нет механизма для применения атрибутов пакета к «клонированным» копиям подпрограмм, используемых в качестве замыканий. (См. «Создание ссылок» в 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. Эти примеры в основном полезны для того, чтобы увидеть, как находится «соответствующий пакет» для возможных поисков методов для определения атрибутов пакета.
-
Код:
package Canine; package Dog; my Canine $spot : Watchful ;Результат:
use attributes (); attributes::->import(Canine => \$spot, "Watchful"); -
Код:
package Felis; my $cat : Nervous;Результат:
use attributes (); attributes::->import(Felis => \$cat, "Nervous"); -
Код:
package X; sub foo : lvalue ;Результат:
use attributes X => \&foo, "lvalue"; -
Код:
package X; sub Y::x : lvalue { 1 }Результат:
use attributes Y => \&Y::x, "lvalue"; -
Код:
package X; sub foo { 1 } package Y; BEGIN { *bar = \&X::foo; } package Z; sub Y::bar : lvalue ;Результат:
use attributes X => \&X::foo, "lvalue";
Последний пример приведен исключительно для полноты. Не следует пытаться изменять атрибуты чего-либо в пакете, который вам не принадлежит.
ДОПОЛНИТЕЛЬНЫЕ ПРИМЕРЫ
-
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. В этой подпрограмме проверяется, запрещен ли какой-либо атрибут, и возвращается список этих «плохих атрибутов».Так как возвращается пустой список, всё в порядке.
-
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.28.3/attributes