问题 如何区分符号表和常规哈希变量?


有没有办法判断哈希引用是否指的是符号表?

也就是说,这个功能怎么可能

sub foo {
    my ($hashref) = @_;
    ...
}

知道它是否被调用为

foo( \%main:: )

而不是

foo( \%main )

应用程序有时是一种功能 tie的哈希变量,但我想避免尝试绑定一个符号表。


2426
2018-03-01 21:31


起源



答案:


看起来这可以通过C API来完成 HvNAME。以下是来自 负责填实perlapi

HvNAME

返回存储的包名称,   如果存储不是存储,则为NULL。看到   SvSTASH,CvSTASH。

  1. char * HvNAME(HV *藏匿处)

7
2018-03-02 00:35



我刚开始从跑步中推断出这一点 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}; - mob


答案:


看起来这可以通过C API来完成 HvNAME。以下是来自 负责填实perlapi

HvNAME

返回存储的包名称,   如果存储不是存储,则为NULL。看到   SvSTASH,CvSTASH。

  1. char * HvNAME(HV *藏匿处)

7
2018-03-02 00:35



我刚开始从跑步中推断出这一点 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}; - mob


您可以查找以“::”结尾的键,这表示它有其他包,或者所有值都是符号引用。

  • 当然,即使在这里,也很难从存储符号的哈希(无论出于何种原因)告诉存储。我正在四处寻找 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::' );
}

表现不是 可怕


3
2018-03-01 21:56



我认为这是一个很好的开始,可以让我95%的路程。对于空包装,此测试不明确(foo(\%empty::package) 与 foo({})并且可能因为误报而被欺骗 foo( { 'abc::' => *main::abc:: }) 或假阴性($emptypkg::{"def"} = "xyz"; foo(\%emptypkg::))。还有什么更万无一失的? - mob