在Perl中检测已声明的包变量 [英] Detecting declared package variables in perl
问题描述
给出
# package main;
our $f;
sub f{}
sub g {}
1;
如何确定 $ f
,但没有声明 $ g
?袖手旁观,我以为 * {main :: g} {SCALAR}
可能是不确定的,但这是善意 SCALAR ref。
How can I determine that $f
, but not $g
, has been declared? Off the cuff, I'd thought that *{main::g}{SCALAR}
might be undefined, but it is a bona fide SCALAR ref.
背景:我想将变量导入 main ::
,但是如果是鲤鱼或鱼,该变量已经声明。
Background: I'd like to import a variable into main::
, but carp or croak if that variable is already declared.
EDIT 添加了 f
子例程来响应@ DVK的最初答案。
EDIT Added an f
subroutine in response to @DVK's initial answer.
ANSWER(2010-07-27)
此并非易事,但有可能。
This isn't easy, but it is possible.
一个 eval
技术是最可移植的,适用于5.10之前的perl。在最近的Perls中,内省模块如 Devel: :Peek
和 B
可以区分。
An eval
technique is most portable, working on perls older than 5.10. In more recent perls, introspective modules like Devel::Peek
and B
can discriminate.
推荐答案
我尽力了,甚至试图询问 eval STRING
是否已经通过<$ c $声明了 $ main :: f
c>我们的或我的
。 (这需要复制,关闭和稍后恢复 STDERR
来减少聊天情况。)更改了程序包后,这些声明在临时切回中不再可见。
I gave it my best, even going so far as trying to ask eval STRING
whether $main::f
had been declared via our
or my
. (This required duping, closing, and later restoring STDERR
to cut down on the chattiness.) Once you've changed packages, those declarations no longer seem visible on a temporary switchback.
下面的技术将检测是否已通过
$ b声明了 $ f
$ b
The technique below will detect whether $f
has been declared via
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;
这篇关于在Perl中检测已声明的包变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!