2011-12-16 14 views
9

Esto es lo que tengo:¿Cómo debo modificar el prototipo para permitir la construcción de un hash después del coderef?

use 5.14.0; 
use strict; 
use warnings; 

sub my_func(&$) { 
    my $coderef = shift; 
    my %attribs = @_; 
} 

Esto es lo que me gustaría lograr:

my_func { 
    print 1; 
} first_attrib => "1",second_attrib => "2"; 

Sin embargo, recibo el error Too many arguments for main::my_func at x.pl line 12, near ""2";". ¿Cómo debo modificar el prototipo para que los parámetros posteriores al coderef se transformen en hash?

Respuesta

8

Si cambia sub my_func(&$) a sub my_func(&%) su código funcionará.

El problema es que no es una first_attrib => "1",second_attrib => "2" ref hachís, sino una lista. Y como señaló friedo, una lista se puede asignar a un hash, aunque una lista con un número impar de elementos podría producir resultados no deseados y generará una advertencia con use warnings.

alternativa, se puede cambiar el código para

sub my_func(&$) { 
    my $coderef = shift; 
    my ($attribs) = @_; 
} 

my_func { 
    print 1; 
} {first_attrib => "1",second_attrib => "2"}; 

para lograr lo que parece querer.

La razón por la que debe envolver $attribs en parens es que la asignación de una matriz a un escalar devuelve solo el número de elementos en la matriz. En este punto @_ es esta matriz:

({first_attrib => "1",second_attrib => "2"}) 

con un ref de hash como un único elemento.

($attribs) = @_; 

dice Perl para crear una matriz anónima con el escalar $attribs ocupa la primera posición, y asignar elementos de @_ a la matriz anónima, elemento por elemento, con lo que $attribs punto en el que el árbitro de hash en @_.

+2

Es más exacto decir que 'first_attrib => "1", second_attrib => "2" 'es una * list *, y una lista se puede asignar a un hash. – friedo

+0

@friedo: Eso es verdad. Gracias por señalar eso. – flesk

3

Necesita realizar los argumentos a un sub de Perl de una lista. Se utiliza el primer elemento de la lista de argumentos para el coderef y los elementos restantes para formar un hash:

#!/usr/bin/env perl 

use 5.14.0; 
use strict; 
use warnings; 

sub my_func(&@) { 
    my $coderef = shift; 
    my %attribs = @_; 
    $coderef->() for keys %attribs; 
} 

my_func { 
    print 1; 
} first_attrib => "1",second_attrib => "2"; 
+2

++, el código funcionará con la llamada tal como está escrita, si el prototipo simplemente se cambia a '(& @)'. – hobbs

+3

@hobbs: O '(&%)', que en mi opinión sería más intuitivo dado lo que OP quiere lograr. – flesk

Cuestiones relacionadas