2011-03-01 38 views
11

有沒有什麼辦法可以判斷一個散列引用是否指向一個符號表?如何區分常規散列變量中的符號表?

也就是說,如何可以在功能

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

知道它是否已經被援引作爲

foo(\%main::) 

而不是

foo(\%main) 

該應用程序是一個函數,有時tie的哈希變量,但我想避免試圖綁定符號表。

回答

7

看起來這可以通過C API使用HvNAME來完成。以下是從perlapi

HvNAME

如果藏匿不是藏匿返回藏匿, 或NULL的包名。見 SvSTASH,CvSTASH。

  1. 的char * HvNAME(HV *藏匿)
+2

我剛剛開始從運行'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 2011-03-02 02:30:28

3

您可以查找以'::'結尾的鍵,這表示它有其他包,或者所有值都是符號引用。

  • 當然,即使在這裏,也很難從哈希中存儲符號(無論出於何種原因)。我在與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::'); 
} 

的表現並不可怕

+0

這是一個很好的開始,並會得到我的方式出現95%,我想。這個測試對於空包('foo(\%empty :: package)'vs'foo({})')是不明確的,並且可能因爲誤報而被欺騙foo({'abc ::'=> * main :: abc ::})或者否定否定('$ emptypkg :: {「def」} =「xyz」; foo(\%emptypkg::)')。更安全嗎? – mob 2011-03-01 22:29:00