2010-08-13 19 views
10

Czy można użyć obiektu jako klucza skrótu?Obiekt jako klucz mieszający

Na przykład, następujący kod pozwala mi korzystać instancję MojaKlasa jako klucz ale gdy iteracyjne nad klawiszami i próba wywołania metody get_value, pojawia się błąd:

nie może zlokalizować metoda obiektu "get_value" za pośrednictwem pakietu "MyClass = hASH (0x12a4040)" (być może zapomniałeś załadować "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; 
} 

Odpowiedz

14

domyślnie wszystkie klawisze skrótu w Perl są struny, więc to, co dzieje się w was kod (który ma inne problemy, jak również), to jest to konwersja obiektu na ciąg znaków i przechowywania ciąg.

Ogólnie, jeśli chcesz użyć obiektu jako klucza, najprostszym sposobem jest użycie dwóch struktur danych, takich, które przechowują twoje obiekty (tablica), i innych, które odwzorowują obiekty na niektóre wartości (hash). Możliwe jest również utworzenie powiązanego skrótu, który będzie obsługiwał obiekty jako klucze, ale ogólnie, powiązane skróty będą wolniejsze niż po prostu przy użyciu dwóch struktur danych.

Standardowy moduł Tie::RefHash zapewnia mechanizm do używania obiektów (i innych odniesień) jako klawiszy skrótu (które działają poprawnie po ich odzyskaniu).

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

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

Wszystko używany jako klawisz krzyżyka jest stringified. Tak więc, używając obiektu jako klucza skrótu, otrzymujesz tylko jego ciągi, a nie sam obiekt.

Prawdziwe pytanie brzmi: dlaczego na świecie chcesz to zrobić?

Ponadto, składnia przypisania wartości do mieszania to $hash{key} = $val; strzałka jest używana, gdy masz do czynienia z hasłem referencyjnym.

Jeśli chcesz powiązać obiekty z inną wartością, jednym ze sposobów byłoby użycie tablicy skrótów, np.

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

Następnie możesz zadzwonić pod numer $foo[0]{obj}->get_value();

Jeśli chcesz tylko do obiektów, aby móc powrócić jakiś unikatowy identyfikator per-instancji, można dodać metodę, która wykorzystuje skalarnych :: util za refaddr operator:

use Scalar::Util 'refaddr'; 

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

... 

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

Więcej: perlobj, perldata, perlreftut, Scalar::Util