【发布时间】:2011-03-01 21:31:20
【问题描述】:
有什么方法可以判断散列引用是否指向符号表?
也就是,怎么会有函数
sub foo {
my ($hashref) = @_;
...
}
知道它是否被调用为
foo( \%main:: )
而不是
foo( \%main )
?
该应用程序是一个函数,有时会处理 tie 的哈希变量,但我想避免尝试绑定符号表。
【问题讨论】:
有什么方法可以判断散列引用是否指向符号表?
也就是,怎么会有函数
sub foo {
my ($hashref) = @_;
...
}
知道它是否被调用为
foo( \%main:: )
而不是
foo( \%main )
?
该应用程序是一个函数,有时会处理 tie 的哈希变量,但我想避免尝试绑定符号表。
【问题讨论】:
看起来这可以通过 C API 使用 HvNAME 完成。以下来自perlapi:
HvNAME
返回一个存储的包名, 如果 stash 不是 stash,则为 NULL。看 SvSTASH , CvSTASH .
- char* HvNAME(HV* stash)
【讨论】:
perl -MDevel::Peek -e 'Dump(\%a::),Dump(\%a)' 推断出这一点。感谢您的链接,这样我就可以减少货物崇拜。如果没有 XS,您仍然可以执行 $is_a_symtable = do { $sv=B::svref_2object($hashref);ref($sv) eq 'B::HV' && $sv->NAME}; 之类的操作
您可以查找以 '::' 结尾的键,这表明它有其他包,或者所有值都是符号引用。
B::svref_2object,但即使是存储在常规哈希中的隐藏符号也会为$sym->can( 'STASH' ) 返回一些东西。我认为您可能会做的事情是遍历符号表并查看存储是否指向完全相同的内存位置。
有点像这样:
use Scalar::Util qw<refaddr>;
my %seen;
sub _descend_symtable {
$calls++;
my ( $cand, $stash_name ) = @_;
my $stash = do { no strict 'refs'; \%{ $stash_name }; };
return if $seen{ refaddr( $stash ) }++;
return $stash_name if $cand == $stash;
my $result;
foreach my $s ( grep { m/::$/ } keys %$stash ) {
$result = _descend_symtable( $cand, "$stash_name$s" )
and return $result;
}
return;
}
sub find_in_symtable {
my $needle = shift;
%seen = ();
return _descend_symtable( $needle, 'main::' );
}
表现并不糟糕。
【讨论】:
foo(\%empty::package) 与 foo({})),此测试将是模棱两可的,并且可能被误报 foo( { 'abc::' => *main::abc:: }) 或误报($emptypkg::{"def"} = "xyz"; foo(\%emptypkg::))欺骗。还有什么更万无一失的吗?