2010-07-30 6 views
6

Je vois des gens qui utilisent deux styles pour passer des paramètres nommés en Perl:passant des paramètres de style en 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' }); 

Quels sont les avantages de l'utilisation foo() le style au lieu de bar() de style?

Répondre

9

La seconde méthode passe une référence à un hachage, tandis que la première passe juste une liste.

Il y a deux aspects ici: en théorie, une référence au hachage pourrait être meilleure en termes de performances, bien que pour les listes d'arguments courts, cela soit négligeable. Pour un appel simple comme foo(a => 1, b => 2), il n'y a pas de différence de performance, car @_ est en réalité un alias aux valeurs d'origine.

Mais si l'appelant a déjà les valeurs dans un hachage, le premier style nécessite une conversion de hachage en liste, puis de nouveau en hachage, qui peut être lent.

Le deuxième aspect est la question de savoir qui est responsable de la conversion en hachage. Le premier style laisse la fonction appelée, et si cela ne fait que my %args = @_, il produira des avertissements curieux si la liste des arguments n'est pas de longueur égale.

C'est pourquoi je préfère légèrement le second style (ou j'utilise Perl 6, qui supporte nativement les arguments nommés).

+1

+1 pour souligner les aspects de performance. –

+1

Ces «aspects de performance» sont des micro-optimisations inutiles qui n'apportent aucun avantage pratique. Un hachage peut être utilisé aussi facilement qu'une liste: 'foo (% hash)' ou un hashref: 'foo (% {$ hashref})'. S'en tenir au style foo laisse plus de puissance à l'utilisateur. – jmz

+0

En fait, mon propre benchmarking a montré (sur plusieurs installations) qu'il est plus rapide de transmettre des listes que des références - bien qu'il semble plus rapide de renvoyer des références. – Axeman

5

D'abord, une explication des deux méthodes:

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'); 

Dans ce premier cas, tout ce que vous faites est de passer un tableau. Le => dans ce contexte n'est pas l'indicateur clé/valeur de hachage que vous pourriez penser. Dans ce contexte, c'est juste une "grosse virgule".

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' }); 

Dans ce second cas, vous créez un hachage anonyme et le passage d'une référence à ce hachage comme argument à la fonction.

Pourquoi choisir l'un plutôt que l'autre? Dans le livre Perl Best Practices, chapitre 9, sous la rubrique «Arguments nommés», l'auteur recommande d'utiliser le deuxième style lorsqu'il y a plus de trois arguments dans la fonction. Il préfère aussi cela parce qu'il attrape des nombres d'arguments incompatibles au moment de la compilation plutôt qu'à l'exécution.

+3

depuis longtemps, mais je pensais que la recommandation d'utiliser un hashref avec 3+ arguments était à la place d'une liste d'arguments non nommée standard, c'est-à-dire appeler 'foo ('a', 'b')', plutôt que recommander des hashrefs sur des hachages – plusplus

+3

@plusplus: Le titre de la section est: "Utilisez un hachage d'arguments nommés pour tout sous-programme ayant plus de trois arguments." Dans le corps de la pièce, il dit spécifiquement d'utiliser un hash ref sur les paires nom/valeur brutes converties en hash. –

+0

+1 pour spécifier votre référence. –

6

Le style foo(a => 1, b => 2) est la manière habituelle d'émuler des arguments nommés. Le bar({a => 1, b => 2}) est généralement utilisé uniquement pour les arguments supplémentaires (et éventuellement facultatifs).

Pour un usage typique, je préfère la première forme. Les {} sont une frappe supplémentaire, un bruit supplémentaire à lire et créent une erreur possible si vous omettez l'une ou l'autre des accolades. Toute différence de performance est négligeable. (Si ce n'est pas le cas, vous avez des problèmes plus importants.) D'un autre côté, envelopper les arguments dans un constructeur de hachage anonyme peut vous aider à trouver des erreurs au moment de la compilation plutôt qu'à l'exécution.

La seconde forme est généralement vue mélangée avec des arguments positionnels. par exemple.Benchmark fait ceci:

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

Alors que Tk quitte le {} sur:

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

Il est généralement un choix stylistique.

Questions connexes