2009-06-03 15 views
6

Mam funkcja, która robi niektóre obliczenia i następnie przechodzi niektóre właściwości do innego podprogramu tak:Jak używać skrótów jako argumentów dla podprogramów w Perlu?

sub get_result { 
    my $id = 1;  
    my %diet = (result => 28, 
       verdict => 'EAT MORE FRUIT DUDE...'  
       ); 

    my %iq = (result => 193, 
       verdict => 'Professor Einstien' 
      );   
    print_result($id, %diet, %iq); 
} 

sub print_result {  
    my $id = shift;  
    my %d = @_;  
    my %i = @_;  

    print "IQ: $id\n";  
    print "DIET RESULT: $d{result}\n";  
    print "DIET VERDICT: $d{verdict}\n";  
    print "IQ RESULT: $i{result}\n";  
    print "IQ VERDICT: $i{verdict}\n";  
}  

Moim problemem jest to, że wyniki drukowane w (dieta rezultacie DIET werdykt) i (IQ wynik IQ WYNIK) są takie same. Tak jakby zmienne% d i% i były zapełniane tymi samymi zmiennymi. Jakieś pomysły, dlaczego tak jest?

jeśli próbuję przeniesienie wszystkich trzech zmiennych tak:

my $id = shift;  
my %d = shift;  
my %i = shift; 

pojawia się następujący błąd:

Odd number of elements in hash assignment 

Odpowiedz

24

Kiedy mijamy tablicę (lub hash) do podprogramu, podprogram będzie uzyskać listę wartości (lub par wartości kluczy). Dlatego nie można przekazać dwóch tablic (lub dwóch skrótów), ponieważ podprogram nie będzie wiedział, gdzie kończy się pierwsza tablica, a druga zaczyna.

Aby obejść ten problem, należy przekazać w odnośnikach zamiast:

my %hash1 = (foo => 'bar'); 
my %hash2 = (bar => 'baz'); 
subroutine(\%hash1, \%hash2); 

sub subroutine { 
    my ($hashref1, $hashref2) = @_; 
    print $hasref1->{foo}, $hashref2->{bar}; 
} 

PS: Oprócz koncepcyjnego problemu, kod znajduje się również w ten sposób:

my %d = @_;  
my %i = @_;  

Jeśli% d i% Obaj mają przypisaną tę samą wartość, nie powinno to być niespodzianką, gdy później są tacy sami.

+0

To działało idealnie. Myślę, że źle interpretowałem odniesienia między różnymi typami. (Scalar, Array, Hash) Dzięki Manni –

+3

Może to być pomocne dla innych, jeśli zaakceptowałeś wtedy odpowiedź. (Nie, żebym miał jakikolwiek wpływ na 25 punktów reputacji.) – innaM

3

Po przejechaniu w %diet i %iq, oboje się spłaszczone do tablicy Arg, więc w swojej print_result, %d zawiera wszystkie elementy w %diet i %iq.

Aby rozwiązać, należy referencje z %diet i %iq:

print_result($id, \%diet, \%iq); 

Następnie w print_result:

my $id = shift; 
my %d = %{+shift}; 
my %i = %{+shift}; 
+2

Twój przykład będzie wyglądał jak haszysz o nazwie shift! Dodaj parens po zmianie, aby tłumacz mógł powiedzieć, że chcesz wywołać funkcję. – mkb

+1

% i nie jest pusty, jest to kopia% d, ponieważ oba są zainicjalizowane z @_. Zobacz odpowiedź Manni. –

+2

Powoduje to utworzenie płytkich kopii obu skrótów.Oznacza to, że zmiany na pierwszym poziomie hasza nie pojawią się w oryginale, ale zmiany na drugim lub późniejszym poziomie. Wygląda na to, że skróty są prostymi skrótami, więc na razie powinno być dobrze (o ile nie oczekuje się, że jakiekolwiek zmiany w haszach będą się rozprzestrzeniać). Jeśli potrzebujesz głębokich kopii, przyjrzyj się funkcji dclone modułu Storable (http://perldoc.perl.org/Storable.html). –

0
use strict; 
use warnings; 

sub get_result { 

    ... 

    print_result($id, \%diet, \%iq); 
    # or 
    print_result($id, {%diet}, {%iq}); 
} 


sub print_result{ 
    my($id, $diet_h, $iq_h) = @_; 
    my %diet = %$diet_h; 
    my %iq = %$iq_h; 

    ... 

} 

czyli

use strict; 
use warnings; 

sub print_result($\%\%); 

sub get_result{ 

    ... 

    print_result($id, %diet, %iq); 
} 

sub print_result($\%\%){ 
    my($id, $diet_h, $iq_h) = @_; 
    my %diet = %$diet_h; 
    my %iq = %$iq_h; 

    ... 

} 
+2

Co powiesz na zrobienie prototypowej odpowiedzi, a nie pierwszej, którą zobaczą? :) –

4

Możesz chcieć sprawdzić moją książkę Intermediate Perl, której jedna trzecia dotyczy referencji i jak z nimi pracować. Obejmuje to przekazywanie złożonych struktur danych do podprogramów, a także inne sposoby, dzięki którym odniesienia ułatwiają życie. :)

some_sub(\%hash); 
some_sub({ key => 'value' }); 
some_sub($hash_ref); 

sub some_sub { 
    my($hash_ref) = @_; 

    ... 
    } 
Powiązane problemy