RÉSUMÉ
À ce stade, après des recherches assez vaste, je suis d'une opinion ferme que dans une situation où une entrée de table de symbole avec le nom « X » a été déclarée mais non affecté à, il est impossible de distinguer génériquement lequel des types de référence dans un glob a été réellement déclaré sans utiliser le sondage approfondi de Devel :: stuff.
En d'autres termes, vous pouvez dire que les 2 situations distinctes:
X n'a pas été déclarée à tous (entrée de table de symbole n'existe pas)
X a été déclaré et certains les types de glob ont été réellement assignés à.
Dans ce second cas,
Vous peut trouver parmi les types de glob ont été affectés à et qui ne sont pas
MAIS, vous ne peut pas figure sur lequel des les types de globaux non affectés à ont été déclarés et non assignés par rapport à ceux qui n'ont pas été déclarés du tout.
En d'autres termes, pour our $f = 1; our @f;
; nous pouvons dire que $main::f
est un scalaire; mais nous ne pouvons pas dire si @f
et %f
ont été déclarés ou non - il ne se distingue pas du tout de our $f = 1; our %f;
. Veuillez noter que les définitions de sous-routine suivent également cette deuxième règle, mais que la déclaration d'un sous nommé lui attribue automatiquement une valeur (le bloc de code), donc vous ne pouvez jamais avoir un sous-nom dans un "déclaré mais non attribué" state (caveat: peut-être pas vrai pour les prototypes ??? aucun indice).
ORIGINAL RÉPONSE
Eh bien, très limité (et à mon avis un peu fragile) solution à distinguer un scalaire à partir d'un sous-programme pourrait être d'utiliser UNIVERSAL :: peut:
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)
}
Résultat :
Declared: $f
Veuillez noter que {SCALAR}
ne semble pas fonctionner à éliminer les non-scalaires dans mes tests - il a heureusement passé par @A
et %H
si je les déclarais et ajouté à la boucle.
MISE À JOUR
J'ai essayé d brian l'approche de foy du chapitre 8 du « Maîtriser perl » et en quelque sorte n'a pas pu obtenir de travailler pour scalaires, hachages ou de tableaux; mais comme il est indiqué ci-dessous par draegtun il travaille pour des sous-routines ou pour les variables qui ont été attribuées à déjà:
> 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, et je n'augmente pas normalement eval() s string. :) C'est plus ou moins mon approche actuelle. Il est important de noter que la vérification eval n'invoque * pas * la méthode FETCH de tie() d scalar - ce serait No Good (tm). Je me demande, est-ce que local() isant $ SIG {__ WARN__} s'occupe des messages d'erreur? – pilcrow
Oui, FWIW, dans mon test si vous localisez le gestionnaire _ \ _ WARN \ _ \ _ (et $ @, aussi, par politesse) avant l'eval, vous faites taire les erreurs sans duppage de descripteur de fichier. – pilcrow