对象作为哈希键

问题描述 投票:0回答:3

是否可以使用对象作为哈希键?

例如,以下代码允许我使用 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;
}
perl hash
3个回答
17
投票

默认情况下,Perl 中的所有哈希键都是字符串,因此您的代码中发生的情况(也存在其他问题)是将对象转换为字符串并存储该字符串。

一般来说,如果您想使用对象作为键,最简单的方法是使用两种数据结构,一种保存对象(数组),另一种将对象映射到某些值(哈希) )。还可以创建一个支持对象作为键的绑定哈希,但一般来说,绑定哈希会比简单使用两个数据结构慢。

标准模块 Tie::RefHash 提供了一种使用对象(和其他引用)作为哈希键的机制(当您取回它们时,它们可以正常工作)。

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

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

8
投票

任何用作哈希键的东西都会被字符串化。因此,当使用对象作为哈希键时,您只会获得它的字符串表示形式,而不是实际的对象本身。

真正的问题是,你到底为什么要这样做?

此外,为哈希值赋值的语法是

$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


0
投票

对于使用 convert_blessed

 对通过 JSON 序列化的对象进行哈希处理:

我们正在序列化使用 JSON 的 TO_JSON 挂钩进行字符串化的对象,并返回一个哈希对象:

sub TO_JSON {
  return { a => { b => 'c'}, d => [1, 2, 3] }
}

之后,使用

JSON::to_json
进行字符串化:

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

Perl 不一致地重新排序

a
d
键,这使得字符串化对象上的散列不可靠。

修复方法是使用

canonical
选项,如下所示:

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

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

© www.soinside.com 2019 - 2024. All rights reserved.