2010-07-30 15 views
6

veo a la gente utilizando dos estilos para pasar parámetros con nombre en Perl:Paso de parámetros de estilo 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' }); 

¿Cuáles son las ventajas en el uso foo) estilo (en lugar de bar() estilo?

Respuesta

9

El segundo método pasa una referencia al hash, mientras que el primero solo pasa una lista.

Aquí hay dos aspectos: en teoría, una referencia al hash podría ser mejor en términos de rendimiento, aunque para las listas de argumentos cortos esto es insignificante. Para una llamada simple como foo(a => 1, b => 2) no hay diferencia de rendimiento, porque @_ es en realidad un alias de los valores originales.

Pero si la persona que llama ya tiene los valores en un hash, el primer estilo requiere conversión de hash a list, y luego de nuevo a hash, que puede ser lento.

El segundo aspecto es la pregunta de quién es responsable de la conversión a un hash. El primer estilo deja la función llamada, y si eso solo hace my %args = @_, producirá advertencias curiosas si la lista de argumentos no tiene una longitud uniforme.

Es por eso que prefiero ligeramente el segundo estilo (o utilizo Perl 6, que admite argumentos con nombre de forma nativa).

+1

+1 para señalar los aspectos de rendimiento. –

+1

Estos "aspectos de rendimiento" son micro-optimizaciones innecesarias que no producen ningún beneficio práctico. Un hash se puede usar tan fácilmente como una lista: 'foo (% hash)' o un hashref: 'foo (% {$ hashref})'. Seguir con el estilo foo deja más poder para el usuario. – jmz

+0

En realidad, mi propia evaluación comparativa ha demostrado (en varias instalaciones) que es más rápido pasar listas que referencias, aunque parece más rápido * devolver * referencias. – Axeman

5

En primer lugar, una explicación de los dos métodos:

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

En este primer caso, todo lo que estamos haciendo está pasando una matriz. El => en este contexto no es el indicador de clave/valor hash que podría pensar. En este contexto, es solo una "coma de grasa".

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

En este segundo caso va a crear un hash anónimo y pasa una referencia a esa almohadilla, como el argumento de la función.

¿Por qué elegir uno sobre el otro? En el libro Perl Best Practices, capítulo 9, bajo el encabezado "Named Arguments", el autor recomienda usar el segundo estilo cuando hay más de tres argumentos para la función. También lo prefiere porque atrapa números de argumentos no coincidentes en tiempo de compilación en lugar de en tiempo de ejecución.

+3

Hace un tiempo que lo leí, pero pensé que la recomendación de usar un hashref con 3+ argumentos era en lugar de una lista de argumentos estándar sin nombre, es decir, llamar 'foo ('a', 'b')', en lugar de recomendando hashrefs sobre hash – plusplus

+3

@plusplus: El título de la sección es: "Use un hash de argumentos nombrados para cualquier subrutina que tenga más de tres argumentos". En el cuerpo de la pieza, dice específicamente que use una referencia hash sobre pares de nombre/valor sin formato convertidos a hash. –

+0

+1 para especificar su referencia. –

6

El estilo foo(a => 1, b => 2) es la forma habitual de emular argumentos con nombre. El bar({a => 1, b => 2}) se usa generalmente solo para argumentos suplementarios (y posiblemente opcionales).

Para el uso típico, prefiero el primer formulario. Los {} son de tipeo extra, ruido extra para leer y crean un posible error si omites alguno o ambos tirantes. Cualquier diferencia de rendimiento es insignificante. (Si no es así, tienes problemas mayores). Por otro lado, envolver los argumentos en un constructor de hash anónimo puede ayudarte a encontrar errores en tiempo de compilación en lugar de en tiempo de ejecución.

La segunda forma se ve típicamente mezclada con argumentos posicionales. p.ej.Benchmark hace esto:

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

Mientras Tk deja el {} a cabo:

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

Por lo general es una opción estilística.

Cuestiones relacionadas