RESUMEN
En este punto, después de bastante extensa investigación, soy de una opinión firme que en una situación cuando una entrada de la tabla de símbolos con el nombre de "X" fue declarado pero no asigna a, es imposible distinguir genéricamente cuál de los tipos de referencia en un glob fue realmente declarado sin utilizar el sondeo profundo de Devel :: stuff.
En otras palabras, se puede decir sólo los siguientes 2 situaciones distintas:
X no fue declarado en absoluto (entrada de la tabla de símbolos no existe)
X fue declarado y algunos de los tipos glob en realidad fueron asignados a.
En este segundo caso,
Usted puede encontrar cuál de los tipos glob fueron asignados a y cuáles no
PERO, que no puede averiguar cuál de las los tipos glob no asignados a declarados y no asignados frente a los que no se declararon en absoluto.
En otras palabras, para our $f = 1; our @f;
; podemos decir que $main::f
es un escalar; pero no podemos decir si @f
y %f
fueron declarados o no - no es distinguible en absoluto de our $f = 1; our %f;
.
Tenga en cuenta que las definiciones de subrutina siguen esta segunda regla también, pero declarar un sub nombrado automáticamente le asigna un valor (el bloque de código), por lo que nunca puede tener un nombre secundario en "declarado pero no asignado" estado (advertencia: puede no ser cierto para los prototipos ??? no hay pista).
respuesta original
Bueno, muy limitado (y en mi humilde opinión un tanto frágil) solución para distinguir un escalar desde una subrutina podría ser el uso UNIVERSAL :: puede:
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)
}
Resultado :
Declared: $f
Tenga en cuenta que {SCALAR}
no parece funcionar para eliminar los non-escalars en mis pruebas, felizmente pasó a través de @A
y %H
si los declaro y agregué al ciclo.
ACTUALIZACIÓN
me trataron enfoque Brian D de Foy del Capítulo 8 de "El dominio de Perl" y de alguna manera era capaz de conseguir que funcione para los escalares, hashes o matrices; pero, como se señala más adelante por draegtun funciona para subrutinas o para las variables que les fueron asignados ya:
> 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
+1, y normalmente no recomiendo stringish eval() s. :) Este es más o menos mi enfoque actual. Es importante destacar que la comprobación de evaluación aquí * no * invoque un método fetch() d escalar FETCH - que sería No bueno (tm). Me pregunto, ¿podría local() izing $ SIG {__ WARN__} hacerse cargo de los mensajes de error? – pilcrow
Sí, FWIW, en mi prueba si localizas el controlador _ \ _ WARN \ _ \ _ (y $ @, también, por cortesía) antes de la evaluación, silencias los errores sin el descriptor de archivo duppery. – pilcrow