2010-07-30 15 views
6

vedo la gente usando due stili per il passaggio di parametri denominati in Perl:parametri che passano stile in Perl

use strict; 
use warnings; 
use Data::Dumper; 

sub foo { 
    print Dumper @_; 
} 

sub bar { 
    print Dumper @_; 
} 

foo(A => 'a', B => 'b'); 
bar({ A => 'a', B => 'b' }); 

Quali sono i vantaggi nell'uso di foo) stile (invece di bar() stile?

risposta

9

Il secondo metodo passa un riferimento all'hash, mentre il primo passa semplicemente una lista.

Ci sono due aspetti qui: in teoria, un riferimento all'hash potrebbe essere migliore in termini di prestazioni, anche se per gli elenchi di argomenti brevi questo è trascurabile. Per una semplice chiamata come foo(a => 1, b => 2) non c'è differenza di prestazioni, perché @_ è in realtà un alias ai valori originali.

Ma se il chiamante ha già i valori in un hash, il primo stile richiede la conversione da hash a elenco e quindi di nuovo su hash, che può essere lento.

Il secondo aspetto è la domanda chi è responsabile della conversione in un hash. Il primo stile abbandona la funzione che viene chiamata, e se lo fa semplicemente my %args = @_, produrrà avvisi curiosi se l'elenco degli argomenti non è di lunghezza uguale.

Ecco perché preferisco leggermente il secondo stile (o io uso Perl 6, che supporta gli argomenti denominati in modo nativo).

+1

+1 per sottolineare gli aspetti prestazionali. –

+1

Questi "aspetti di prestazione" sono micro-ottimizzazioni non necessarie che non apportano alcun vantaggio pratico. Un hash può essere usato facilmente come un elenco: 'pippo (% hash)' o un hashref: 'pippo (% {$ hashref})'. Attaccare con lo stile foo lascia più potere all'utente. – jmz

+0

In realtà, il mio benchmarking ha mostrato (su più installazioni) che è più veloce passare le liste che i riferimenti - anche se sembra più veloce ai riferimenti * return *. – Axeman

5

In primo luogo, una spiegazione dei due metodi:

sub foo { 
    # Transform the array to a hash 
    my %args = @_; 

    foreach my $key (keys %args) { 
     print "$key => $args{$key}\n"; 
    } 
} 

# Pass an array of values 
foo(A=>'a', B=>'b'); 

In questo primo caso tutto quello che stai facendo sta passando un array. Lo => in questo contesto non è l'indicatore di chiave/valore hash che si potrebbe pensare. In questo contesto è solo una "fat comma".

sub bar { 
    my ($hash_ref) = @_; 
    foreach my $key (keys %$hash_ref) { 
     print "$key => $hash_ref->{$key}\n"; 
    } 
} 

# pass a ref to an anonymous hash 
bar({ A=>'a', B=>'b' }); 

In questo secondo caso si sta creando un hash anonimo e passando un riferimento a tale hash come argomento della funzione.

Perché scegliere l'uno rispetto all'altro? Nel libro, Perl Best Practices, capitolo 9 sotto l'intestazione "Argomenti nominali", l'autore raccomanda di utilizzare il secondo stile quando ci sono più di tre argomenti per la funzione. Lo preferisce anche perché cattura numeri di argomenti non corrispondenti in fase di compilazione piuttosto che in fase di esecuzione.

+3

è da un po 'che l'ho letto, ma ho pensato che la raccomandazione di utilizzare un hashref con 3+ argomenti fosse invece di un elenco di argomenti senza nome standard, ovvero chiamare 'foo (' a ',' b ')', piuttosto che raccomandare hashrefs su hashes – plusplus

+3

@plusplus: il titolo della sezione è: "Utilizzare un hash di argomenti denominati per qualsiasi subroutine che abbia più di tre discussioni". Nel corpo del pezzo dice esplicitamente di usare un hash ref su coppie nome/valore non elaborate convertite in un hash. –

+0

+1 per specificare il riferimento. –

6

Lo stile foo(a => 1, b => 2) è il solito modo di emulare argomenti denominati. Il bar({a => 1, b => 2}) viene in genere utilizzato solo per argomenti supplementari (e eventualmente facoltativi).

Per l'utilizzo tipico, preferisco il primo modulo. Il {} è una digitazione aggiuntiva, un rumore extra da leggere e crea un possibile errore se si omette una o entrambe le parentesi. Qualsiasi differenza di prestazioni è trascurabile. (Se non lo è, hai problemi più grandi.) D'altra parte, il wrapping degli argomenti in un costruttore di hash anonimo può aiutarti a trovare errori in fase di compilazione piuttosto che in runtime.

Il secondo modulo viene in genere visualizzato in combinazione con argomenti posizionali. per esempio.Benchmark fa questo:

cmpthese(10000, { 
    foo => \&foo, 
    bar => \&bar, 
}); 

Mentre Tk lascia l'{} out:

my $text = $w->Scrolled('Text', -width => 80, -height => 50); 

Di solito è una scelta stilistica.

Problemi correlati