Что такое таблица имен (symbol table) в Perl?
Для каждого пакета в Perl создается таблица имен. Таблица имен представляет собой хеш, имя которого совпадает с именем пакета. Ключами этого хеша являются имена глобальных переменных (а так же функций, указателей файлов и т.п.), определенных в текущем пакете. Значения хеша таблицы имен — переменные типа typeglob, которые содержат значения объявленных глобальных переменных.
Новая запись в таблице имен создается в тот момент, когда происходит объявление новой
глобальной переменной. Лексические переменные и «локальные» функции в таблицу не вносятся.
Если для текущего кода пакет не объявлен (директивой package), запись будет помещена в таблицу имен %main:: .
В таблицу имен пакета, отличного от main, могут включаться только те идентификаторы, имена которых начинаются с буквы или символа подчеркивания.
Таблица имен существует только в момент работы интерпретатора, и хранится в памяти компьютера. Таблицы имен используются для доступа к используемым пакетам и их данным. Любой perl-скрипт может напрямую обращаться к содержимому таблиц имен.
Справка: Что такое пакет main?
Main — это пакет верхнего уровня.
Perl поддерживает два специальных имени пакетов:
- main — пространство имен главной программы. Используется по умолчанию.
- CORE — пространство имен встроенных функций.
Через main можно получить доступ ко всем используемым в программе пакетам.
Справка: Что такое typeglob?
typeglob — это особенный, внутренний тип данных в perl. Принадлежность к этому типу данных обозначается префиксом «*» . Префикс «*» можно рассматривать как метасимвол, вместо которого может стоять любой из префиксов «$», «@», «%», «&». Т.е. переменная типа typeglob может содержать в себе что угодно.
Переменную типа typeglob можно представить как небольшой хеш, ключами которого выступают имена типов данных. В зависимости от типа данных, размещенных в переменной typeglob, для их извлечения можно обратиться к соответствующим полям.
Для получения данных из записей таблицы имен можно использовать поля:
- PACKAGE — имя пакета, в котором определен текущий идентификатор (имя переменной).
- NAME — имя идентификатора.
- SCALAR — ссылка на скалярную переменную идентификатора (если это скалярная переменная).
- ARRAY — ссылка на массив (если переменная является массивом).
- HASH — ссылка на хеш (если переменная является хешом).
- CODE — ссылка на подпрограмму (если идентификатор был создан при объявлении функции).
- IO, FILEHANDLE — Ссылка на указатель файла.
- GLOB — Ссылка на typeglob для идентификатора.
Пример 1:
Любая глобальная переменная помещается в пространство имен своего пакета. Можно получить доступ к ее значению, используя таблицу имен. В таблице имен она будет иметь тип данных typeglob, поэтому обращаться к ней нужно через префикс «*».
$variable = 5;
print ${*variable{SCALAR}}; # выведет 5
Пример 2:
use CGI;
print ${*CGI::VERSION{SCALAR}}; # выведет 3.43
Примеры кода
Пример 1
Вывод содержимого пакета main.
#!/usr/local/bin/perl
foreach (keys %main::) {
print $_." => ".$main::{$_}."\n";
}
Результат:
%perl main1.pl version:: => *main::version:: / => *main::/ stderr => *main::stderr _*main::_ *main::CORE:: mro:: => *main::mro:: stdout => *main::stdout attributes:: => *main::attributes:: => *main:: stdin => *main::stdin ARGV => *main::ARGV INC => *main::INC ENV => *main::ENV Regexp:: => *main::Regexp:: UNIVERSAL:: => *main::UNIVERSAL:: _ *main::_ *main::PerlIO:: 0 => *main::0 _ *main::_ *main::STDOUT IO:: => *main::IO:: _ => *main::_ STDERR => *main::STDERR Internals:: => *main::Internals:: STDIN => *main::STDIN DB:: => *main::DB:: ... _ *main::_ Пример 2
Допустим, нам хочется получить побольше информации о переменной %ENV, через таблицу имен:
print *main::ENV{HASH}; foreach (keys %{*main::ENV{HASH}}) { print $_." => ".${*main::ENV{HASH}}{$_}."\n"; }Так мы получили полный список переменных окружения и их значений:
%perl main1.pl HASH(0x800e3e918)SSH_CLIENT => 194.85.195.166 4641 22 HOME => /home/natalie SSH_CONNECTION => 194.85.195.166 4641 194.85.61.131 22 BLOCKSIZE => K OSTYPE => FreeBSD EDITOR => vi VENDOR => unknown USER => natalie GROUP => httpd-natalie SHLVL => 2 ...Пример 3
Очень простой пример. Объявляем глобальную переменную $count.
Т.к. этот простой скрипт не объявлен как пакет, переменная помещается в пространство имен пакета main. А потом получаем значение переменной через таблицу имен.our $count = 123; print ${*main::count};Результат:
%perl main1.pl 123В самом деле, использование полей CODE, ARRAY и др. для доступа к значению переменной совсем не обязательно. Однако, в этом случае надо точно знать, ссылку на значение какого типа вернет обращение к таблице имен. Потому что, ссылку нужно соответствующим образом разыменовать. Как это сделать, если вы не имеете никакого понятия, что подразумевается под именем переменной?
В данном примере, count мог оказаться не только скалярной переменной, но и именем массива, и функцией. Если вы работаете с переменной своего модуля - проблем не возникнет. Но если вы импортируете переменные из стороннего пакета - использовать обращение к полям CODE и пр. может оказаться удобнее.
Пример 4
Можно получить доступ не только к переменным пакета, но и к подпрограммам. Получаем ссылку на подпрограмму, разыменовываем ее и заставляем выполниться.
use Digest::MD5; print &{*Digest::MD5::md5_hex{CODE}}("dddd"); # выведет 11ddbaf3386aea1f2974eee984542152Полезные ссылки
Perl. Тип данных typeglob и записи в таблице символов
Таблицы символов и пространства имен
Symbols, Symbol Tables and Packages; Typeglobs
Поделись ссылкой с друзьями!
Комментариев нет
Комментариев нет.
RSS-лента комментариев к этой записи.