Подтвердить что ты не робот

Как вам отличить таблицу символов от обычной хэш-переменной?

Можно ли указать, ссылается ли ссылка на хеш-ссылку на таблицу символов?

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

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

знать, был ли он вызван как

foo( \%main:: )

а не

foo( \%main )

?

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

4b9b3361

Ответ 1

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

HvNAME

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

  • char * HvNAME (HV * stash)

Ответ 2

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

  • Разумеется, даже здесь было бы сложно сказать, что из хэша можно просто хранить символы (по какой бы то ни было причине). Я ткнулся с B::svref_2object, но даже символы из тайника, хранящегося в регулярном хеше, вернут что-то для $sym->can( 'STASH' ).

Я думаю, что вещь, которую вы можете сделать, - это спуститься через таблицу символов и посмотреть, указывает ли 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::' );
}

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