РЕЗЮМЕ
На данный момент, после довольно обширных исследований, я твердо убежден, что в ситуации, когда запись в таблице символов с именем "X" была объявлена, но не присвоена, невозможно вообще отличить какой из ссылочных типов в глобале был фактически объявлен без использования глубокого исследования Devel :: stuff.
Другими словами, вы можете сказать только следующие 2 различные ситуации:
X не был объявлен вообще (запись таблицы символов не существует)
X был объявлен, и некоторые типы глобусов были фактически назначены.
Во втором случае
Вы можете найти, КАКОЙ из типов глобусов был присвоен, а какие не были
НО, вы не можете выяснить, какие типы глобусов, не назначенные для, были объявлены и не назначены, а какие не были объявлены вообще.
Другими словами, для our $f = 1; our @f;
; мы можем сказать, что $main::f
- скаляр;
но мы НЕ можем сказать, были ли объявлены @f
и %f
или нет - это ничем не отличается от our $f = 1; our %f;
.
Обратите внимание, что определения подпрограмм также следуют этому второму правилу, но объявление именованного подпрограммы автоматически присваивает ему значение (блок кода), поэтому у вас никогда не может быть подимен в состоянии «объявлен, но не присвоен». (предостережение: может быть, это не так для прототипов ??? без понятия).
ОРИГИНАЛЬНЫЙ ОТВЕТ
Ну, очень ограниченным (и ИМХО несколько хрупким) решением отличить скаляр от подпрограммы может быть использование UNIVERSAL :: can:
use strict;
our $f;
sub g {};
foreach my $n ("f","g","h") {
# First off, check if we are in main:: namespace,
# and if we are, that we are a scalar
no strict "refs";
next unless exists $main::{$n} && *{"main::$n"};
use strict "refs";
# Now, we are a declared scalr, unless we are a executable subroutine:
print "Declared: \$$n\n" unless UNIVERSAL::can("main",$n)
}
Результат:
Declared: $f
Обратите внимание, что {SCALAR}
, похоже, не работает для отсеивания нескаляров в моем тестировании - оно успешно прошло через @A
и %H
, если я их объявил и добавил в цикл.
UPDATE
Я попробовал подход Брайана Д Фоя из главы 8 «Освоение perl» и почему-то не смог заставить его работать для скаляров, хэшей или массивов; но, как отмечено ниже, draegtun работает для подпрограмм или для переменных , которые уже были назначены :
> perl5.8 -we '{use strict; use Data::Dumper;
our $f; sub g {}; our @A=(); sub B{}; our $B; our %H=();
foreach my $n ("f","g","h","STDOUT","A","H","B") {
no strict "refs";
next unless exists $main::{$n};
print "Exists: $n\n";
if ( defined ${$n}) { print "Defined scalar: $n\n"};
if ( defined @{$n}) { print "Defined ARRAY: $n\n"};
if ( defined %{$n}) { print "Defined HASH: $n\n"};
if ( defined &{$n}) { print "Defined SUB: $n\n"};
use strict "refs";}}'
Exists: f
Exists: g
Defined SUB: g <===== No other defined prints worked
Exists: STDOUT
Exists: A
Exists: H
Exists: B
Defined SUB: B <===== No other defined prints worked