SUMMARY
在这一点上,经过相当广泛的研究,我坚信,在声明了名称为“X”的符号表条目但未分配给它的情况下,它是无法笼统区分glob 中的哪些引用类型实际上是在没有使用 Devil:: stuff 的深度探测的情况下声明的。
换句话说,您只能区分以下两种不同的情况:
X 根本没有声明(符号表条目不存在)
-
X 已声明,并且实际分配了一些 glob 类型。
在第二种情况下,
换句话说,对于our $f = 1; our @f;
;我们可以说$main::f
是一个标量;
但我们无法判断是否@f
and %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)
}
Result:
Declared: $f
请注意{SCALAR}
在我的测试中似乎无法清除非标量 - 它很高兴地通过了@A
and %H
如果我声明它们并添加到循环中。
UPDATE
我尝试了《Mastering Perl》第 8 章中的 Brian d Foy 的方法,但不知何故无法让它适用于标量、散列或数组;但正如下面 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