Как вам отличить таблицу символов от обычной хеш-переменной? - PullRequest
11 голосов
/ 02 марта 2011

Есть ли способ определить, ссылается ли ссылка на хеш на таблицу символов?

То есть, как функция

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

может узнать, была ли она вызвана как

foo( \%main:: )

вместо

foo( \%main )

?

Приложение - это функция, которая иногда хеш-переменные tie, но я бы хотел избежать попытки связать таблицу символов.

Ответы [ 2 ]

7 голосов
/ 02 марта 2011

Похоже, что это можно сделать из C API, используя HvNAME. Следующее от perlapi :

HvNAME

Возвращает имя пакета тайника, или NULL, если тайник не является тайником. Увидеть СвСТАШ, CvSTASH.

  1. char * HvNAME (HV * stash)
3 голосов
/ 02 марта 2011

Вы могли бы искать либо ключи, заканчивающиеся на '::', которые указывали бы, что у него есть другие пакеты, либо все значения являются символьными ссылками.

  • Конечно, даже здесь это будетТрудно отличить тайник от хэша, который просто хранит символы (по какой-либо причине).Я копался с 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::' );
}

Спектакль не был ужасен .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...