perl 对象作为哈希键

waxmsbnn  于 12个月前  发布在  Perl
关注(0)|答案(3)|浏览(166)

是否可以使用对象作为哈希键?
例如,下面的代码允许我使用MyClass的示例作为键,但是当我遍历这些键并试图调用get_value方法时,我得到了错误:

无法通过包“MyClass=HASH(0x12a4040)”定位对象方法“get_value”(可能您忘记加载“MyClass=HASH(0x12a4040)"?)

package MyClass;
use strict;

sub new
{
    my $class = shift;
    my $self = {
        _value => shift
    };
    bless $self, $class;
    return $self;
}

sub get_value {
    my($self) = @_;
    return $self->{_value};
}

my %hash = ();
%hash->{new MyClass(1)} = 0;
%hash->{new MyClass(2)} = 1;

for my $key (keys %hash)
{
    print $key->get_value;
}
u7up0aaq

u7up0aaq1#

默认情况下,Perl中的所有哈希键都是字符串,所以在代码中发生的事情(也有其他问题)是将对象转换为字符串并存储字符串。
一般来说,如果你想使用一个对象作为键,最简单的方法是使用两个数据结构,一个保存你的对象(数组),另一个将对象Map到一些值(哈希)。也可以创建一个绑定哈希,它将支持对象作为键,但通常,绑定哈希会比简单地使用两个数据结构慢。
标准模块Tie::RefHash提供了一种使用对象(和其他引用)作为散列键(当您取回它们时,它们可以正常工作)的机制。

use Tie::RefHash;
tie my %hash, 'Tie::RefHash';

$hash{MyClass->new(1)} = 0;  # never use the indirect object syntax
....
dy1byipe

dy1byipe2#

任何用作散列键的东西都是字符串化的。所以当你把对象用作散列键时,你只会得到它的字符串表示,而不是实际的对象本身。
真实的问题是,你到底为什么要这么做?
此外,将值赋给哈希的语法是$hash{key} = $val;箭头用于处理哈希引用。
如果你想将对象与其他值相关联,一种方法是使用哈希数组,例如。

my @foo;
push @foo, { obj => MyClass->new( 1 ), val => 0 };
push @foo, { obj => MyClass->new( 2 ), val => 1 };

然后你可以调用$foo[0]{obj}->get_value();
如果你只是想让你的对象能够返回一些唯一的每个示例的ID,你可以添加一个方法,利用Scalar::Util的refaddr运算符:

use Scalar::Util 'refaddr';

sub unique_id { 
    my $self = shift;
    return refaddr $self;
}

...

$hash{MyClass->new(1)->unique_id} = 0;

更多信息:perlobjperldataperlreftutScalar::Util

iecba09b

iecba09b3#

对于那些使用convert_blessed对JSON序列化的对象进行散列:
我们使用JSON的TO_JSON钩子序列化字符串化的对象,并返回一个哈希对象:

package FromAbove;

sub new { 
  my ($class, %args) = @_;
  return bless(\%args, $class)
}

sub TO_JSON {
  my $self = shift;
  return { %$self };
}
1;

然后,使用JSON::to_json进行字符串化:

my $object_from_above = FromAbove->new( a => { b => 'c'}, d => [1, 2, 3] );
my $json_string = JSON::to_json($object_from_above, { convert_blessed => 1 });

Perl对ad键的重新排序不一致,这使得字符串化对象上的散列不可靠。
修复方法是使用canonical选项,如下所示:

my $json_string = JSON::to_json($object_from_above, {
  convert_blessed => 1,
  canonical => 1 # the fix
});

注:大对象将有巨大的JSON键,所以要小心。

相关问题