给定
# package main;
our $f;
sub f{}
sub g {}
1;
如何确定
$f
,但不是 $g
,已经宣布了吗?袖手旁观,我以为*{main::g}{SCALAR}
可能未定义,但它是真正的 SCALAR 引用。背景:我想将一个变量导入
main::
, 但如果该变量已声明,则为 carp 或 croak。编辑 添加了
f
响应@DVK 的初始回答的子程序。回答 (2010-07-27)
这并不容易,但有可能。
一个
eval
technique是最便携的,在 5.10 之前的 perls 上工作。在最近的 perls 中,像 Devel::Peek
这样的内省(introspection)模块和 B
可以歧视。
最佳答案
总结
在这一点上,经过相当广泛的研究,我坚定地认为,在一个名为“X”的符号表条目被声明但未分配给它的情况下,它是。无法普遍区分 glob 中的哪些引用类型实际上是通过对 Devel::的深入探测而声明的。
换句话说,您只能说出以下两种不同的情况:
在第二种情况下,
换句话说,对于
our $f = 1; our @f;
;我们可以看出$main::f
是一个标量;但我们无法判断
@f
和 %f
是否已声明 - 它与 our $f = 1; our %f;
完全没有区别.请注意,子例程定义也遵循第二条规则,但是声明一个命名的 sub 会自动为其分配一个值(代码块),因此您永远不能有一个处于“已声明但未分配给”状态的子名称(警告:原型(prototype)可能不是真的???没有线索)。
原始答案
好吧,将标量与子例程区分开来的非常有限(恕我直言有些脆弱)的解决方案可能是使用 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
如果我声明它们并添加到循环中。更新
我从“掌握 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
关于perl - 在 perl 中检测声明的包变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3335425/