特定
# 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
和B
可以区别对待.
解决方法
我尽我所能,甚至试图询问eval STRING是否已经通过我们或我的声明$main :: f. (这需要重复,关闭,以及稍后恢复STDERR以减少干扰.)一旦你更改了包,那些临时转回的声明就不再可见了.
下面的技术将检测是否已通过声明$f
use vars qw/ $f /;
代码如下:
package MyModule; use warnings; use strict; # using $f will confuse the compiler,generating # warnings of 'Variable "%f" is not available' # although we're going for $main::f my $__f = "from MyModule"; my %IMPORT_OK = ( '$f' => [f => \$__f],); sub import { my($pkg,@imports) = @_; my $callpkg = caller; die "I don't speak your dirty Pig-Latin" if $callpkg !~ /\A\w+(::\w+)*\z/ || grep !/\A[\$@%]\w+\z/,@imports; foreach my $name (@imports) { my($sym,$ref) = @{ $IMPORT_OK{$name} || [] }; die "unknown import: $name" unless $sym; open my $saverr,">&",\*STDERR or die "dup STDERR: $!"; close STDERR; my $declared = eval qq{ package $callpkg; my(undef)=$name; 1; }; open STDERR,$saverr or print "restore STDERR: $!"; die "${callpkg}::$sym already exists" if $declared; { no strict 'refs'; *{$callpkg . "::" . $sym} = $ref; } } } 1;