Strange behavior of a tied hash in perl, when asking for an arrayref

末鹿安然 提交于 2019-12-12 10:51:49

问题


I was trying to tie an hash (or hashref) in order of tracking variable usages.

Everything is working for simple cases, but when I tried to use my module on some real code I had this error:

hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this)

I've replicated the error using the following code:

use Tie::Hash::Usages;
use JSON;

my @arr = (
    {
        key1 => "ac",
        key2 => 12,
        key3 => 12
    },        
);
my %tied_hash;


tie %tied_hash, 'Tie::Hash::Usages';

$tied_hash{key1} = \@arr;

my @val = $tied_hash{key1};
print encode_json(\@val)."\n\n"; #this works

print encode_json($tied_hash{key1}); #this doesn't

The same code works with a plain hash.

I'd need this to work also in the second case, the code base is huge and I don't want to change it or live with the doubt that something somewhere will not work in some particular case.

Usages.pm (simplified)

package Tie::Hash::Usages;
use strict;
use warnings;

use Tie::Hash;

use vars qw(@ISA);

@ISA = qw(Tie::StdHash);

sub TIEHASH {

    my ($class, $tracker, $filename) = @_;
    my %hash;

    bless \%hash, $class;

}

sub STORE {
    my ($self, $key, $val) = @_;
    $self->{$key} = $val;
}

sub DELETE {
    my ($self, $key) = @_;
    delete $self->{$key};

}

sub FETCH {
    my ($self, $key) = @_;
    return $self->{$key};
}

sub DESTROY {
    my $self = shift;
}
1;

perl version: v5.18.2


回答1:


Minimal demonstration:

use JSON::XS  qw( encode_json );
use Tie::Hash qw( );

our @ISA = 'Tie::StdHash';

{
   tie my %tied, __PACKAGE__;
   $tied{data} = { a => 1 };
   encode_json($tied{data});  # Exception: hash- or arrayref expected ...
}

JSON is a front-end for JSON::PP (default) or JSON::XS (if found). This is a problem with JSON::XS.

A lot of XS code doesn't handle magical variables (which is what $tied{EXPR} returns), and while JSON::XS has handled magical values since version 1.2, it doesn't for the value directly passed to encode_json.

This is an existing bug in JSON::XS that can be worked around as follows:

encode_json(my $non_magical = $tied{data})

Bug reported.




回答2:


Unable to replicate using the code given, so what you're providing doesn't seem to be representative of your actual situation. The only thing I see that's the tiniest bit off is this line:

my @val = $tied_hash{key1};

in which you're assigning a scalar (your stored arrayref) to an array. Perl handles this fine, assembling an array with the scalar as sole content, but if your actual use case involves something more complex (maybe something with sub prototypes involved), conceivably something might be going wrong there.




回答3:


Ether got it right. JSON library uses JSON:XS by default (which creates this issue). All I had to do is uninstall JSON::XS and install JSON::PP

  1. sudo cpan
  2. install cpan App::cpanminus
  3. exit
  4. sudo cpanm --uninstall JSON::XS
  5. sudo cpan
  6. install JSON::PP
  7. exit

Hope this helps someone.



来源:https://stackoverflow.com/questions/33738849/strange-behavior-of-a-tied-hash-in-perl-when-asking-for-an-arrayref

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!