2010-02-12 14 views
7

Ho una classe con un metodo che restituisce un hash. Normalmente, vorrei avere il risultato in questo modo:Come posso annullare un hash restituito da un metodo di una classe?

%resp = $myclass->sub($foo); 

E poi i membri di accesso della hash restituita in questo modo:

$resp{key}{subkey}; 

nel caso di un hash 2d.

Immagino che ci deve essere un modo per combinare questo in un unico, linea elegante, qualcosa di simile:

$myclass->sub($foo)->{key}{subkey} 

Questo ovviamente non viene dereference correttamente come Perl restituisce questo quando si cerca di eseguire il codice:

Can't use string ("1/8") as a HASH ref

Nel tentativo sequenze dereferenziamento casuali, dal guardare "References quick reference" on Perlmonks, mi si avvicinò con la seguente, che Perl non si lamenta, ma anche non restituisce quello che sto cercando:

$%{$myclass->sub($foo)}->{key}{subkey} 

Qualcuno può dirmi che cosa è la sequenza di fuga magica di dereferenziamento?

+1

Tutti sembrano voler rendere le vite più difficili girando due linee perfettamente in una riga incasinata. Sicuramente ci sono cose migliori a cui pensare. :) –

risposta

1

Basta tornare un rifhash invece di un hash:

$myclass->sub($foo)->{key}->{subkey}

+0

Stesso risultato come con -> prima di {chiave}. Grazie. – sgsax

+0

Lo stesso risultato anche se tolgo -> del tutto. – sgsax

+0

Whazzup con -1? La seconda soluzione ha funzionato. – DVK

2

mi piacerebbe tornare un riferimento ad hash dal sub invece. In caso contrario (probabilmente) il vostro hash è trasformato in un LISTA poi in un hash di nuovo senza motivo:

sub mysub() { 
    ... 
    return \%myhash; 
} 

C'è meno la copia coinvolti quando si ritorna il riferimento, quindi, più efficiente.

+2

l'hash viene trasformato in un elenco, non in un array. la distinzione è sottile ma importante. –

+0

Posso farlo funzionare. Puoi spiegare il vantaggio di restituire un hashref invece di un hash? Posso rielaborare gli altri metodi della classe abbastanza facilmente. Grazie! – sgsax

+0

Grazie Eric. Volevo scrivere LISTA ma è passato un po 'di tempo. Il mio Perl è piuttosto arrugginito ora. – ziya

6

Cambiare il sub per restituire un riferimento ad hash avrebbe funzionato meglio, ma per ottenere la funzionalità che sono alla ricerca di:

{ $myclass->sub($foo) }->{key}{subkey} 

che creerà un riferimento hash dalla lista restituita da sub, e poi subito dereference it

Modifica: il vantaggio di restituire un hashref dal sub piuttosto che un hash (come elenco) è in gran parte una delle prestazioni. Nel caso di hashref, l'hash viene creato una sola volta e quindi acceduto. Nell'elenco di casi, l'hash viene creato, quindi convertito in un elenco, quindi creato nuovamente e quindi sottoposto a dereferenziazione. Per piccoli hash questo non richiede troppo tempo, ma per quelli più grandi, è solo un lavoro non necessario per il runtime. In sostanza, se si prevede di utilizzare i dati come elenco in alcuni punti e come hash in altri, restituire l'hash come elenco è ok. Ma se hai sempre intenzione di usarlo come un hash, restituire il riferimento è più chiaro e più veloce.

+0

Questo mi fa esattamente ciò che stavo cercando mantenendo il mio codice di classe esistente. Grazie! – sgsax

9

Quello che stai cercando di fare non è né elegante né consigliabile. In qualche modo sei riuscito a richiamare la routine in un contesto scalare (questo è ciò che corrisponde a "1/8").

Restituisce un riferimento hash.

Ora, date un'occhiata a:

#!/usr/bin/perl 

package My::Mine; 

use strict; use warnings; 

sub test { 
    my %h = (
     a => { z => 1}, 
     b => { y => 2}, 
    ); 
    return %h; 
} 

package main; 

use strict; use warnings; 

my $class = 'My::Mine'; 

print { $class->test }->{a}{z}, "\n"; 

che non funzionano. Invece, si dovrà fare:

print +{ $class->test }->{a}{z}, "\n"; 

Ora, che è elegante Vedi perldoc -f print (Non !).

Per farla breve, restituire un riferimento all'hash.

Si noti che il nuovo hash anonimo che si sta costruendo non è gratuito. Né è il costo di restituire un hash come una lista semplice da una subroutine.

+0

Non capisco per cosa viene usato il + qui. Apprezzo l'educazione. Grazie. – sgsax

+3

+1 per spiegare chiaramente 1/8. Inoltre, un altro svantaggio di restituire un hash - ti cullerà in un falso senso di sicurezza se pensi "questa è una copia, quindi posso tranquillamente modificarla" - eppure gli interni della struttura dati sono ancora refs che non lo sono deep cloned in modo da non poterli modificare in modo sicuro. – DVK

+2

il + è un suggerimento per il parser che il costrutto {...} dopo la stampa non è un oggetto indiretto per il metodo di stampa. questo è usato in situazioni come 'print {sub_returns_a_file_handle()}" cose da stampare - nota che non c'è una virgola prima dell'open citazione ";' –

0

Se si desidera sempre ottenere solo una sottochiave, scrivere una subroutine breve per farlo e dimenticare di giocare a golf la linea. Un vantaggio è che puoi facilmente aggiungere qualche controllo di integrità:

sub get_subkey { 
     my($class, $arg, $key, $subkey) = @_; 

     my $hashref = $class->method($arg); 
     return unless ref $hashref; 

     return $hashref->{$key}{$subkey}; 
     } 
Problemi correlati