Объект как хеш-ключ - PullRequest
       1

Объект как хеш-ключ

12 голосов
/ 13 августа 2010

Возможно ли использовать объект в качестве хеш-ключа?

Например, следующий код позволяет мне использовать экземпляр MyClass в качестве ключа, но когда я перебираю ключи и пытаюсь вызватьget_value метод, я получаю ошибку:

Не удается найти метод объекта "get_value" через пакет "MyClass = HASH (0x12a4040)" (возможно, вы забыли загрузить "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;
}

Ответы [ 2 ]

16 голосов
/ 13 августа 2010

По умолчанию все ключи хеширования в Perl являются строками, поэтому в вашем коде (который также имеет другие проблемы) происходит преобразование объекта в строку и сохранение строки.

В общем, если вы хотите использовать объект в качестве ключа, самый простой способ сделать это - использовать две структуры данных, одну, которая содержит ваши объекты (массив), а другую, которая отображает объекты в некоторые значения (хеш),Также возможно создать связанный хеш, который будет поддерживать объекты в качестве ключей, но в целом связанные хэши будут работать медленнее, чем просто использование двух структур данных.

Стандартный модуль Tie :: RefHash предоставляет механизм для использования объектов (и других ссылок) в качестве ключей хеша (которые работают правильно, когда вы их возвращаете).

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

$hash{MyClass->new(1)} = 0;  # never use the indirect object syntax
....
8 голосов
/ 13 августа 2010

Все, что используется в качестве хеш-ключа, является строковым. Поэтому при использовании вашего объекта в качестве хеш-ключа вы получаете только строковое представление о нем, а не сам фактический объект.

Реальный вопрос в том, почему в мире вы хотели бы сделать это?

Кроме того, синтаксис для присвоения значений хешу: $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();

Если вы просто хотите, чтобы ваши объекты могли возвращать какой-то уникальный идентификатор для каждого экземпляра, вы можете добавить метод, который использует оператор Scalar :: Util's refaddr:

use Scalar::Util 'refaddr';

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

...

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

Для получения дополнительной информации: perlobj , perldata , perlreftut , Scalar :: Util

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