在perl中检测声明的包变量

pil*_*row 9 variables perl declaration

特定

# package main;
our $f;
sub f{}
sub g {}
1;
Run Code Online (Sandbox Code Playgroud)

我怎样才能确定$f,但是没有$g宣布?关闭袖口,我认为*{main::g}{SCALAR}可能是未定义的,但它是一个真正的 SCALAR参考.

背景:我想将一个变量导入main::,但是如果已经声明了该变量,则将carp或croak 导入.

编辑添加了一个f子程序来响应@ DVK的初始答案.

答案(2010-07-27)

这并不容易,但有可能.

一种eval技术是最便携的,工作在早于5.10的perls上.在最近的perls中,内省模块喜欢Devel::PeekB可以区别对待.

Gre*_*con 1

我尽了最大努力,甚至试图询问eval STRING是否$main::f已通过our或声明my。(这需要复制、关闭,然后恢复STDERR以减少麻烦。)一旦更改了包,这些声明在临时之字形上就不再可见。

下面的技术将检测是否$f已通过声明

use vars qw/ $f /;
Run Code Online (Sandbox Code Playgroud)

代码如下:

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;
Run Code Online (Sandbox Code Playgroud)