¿Es significativo el orden en el que se pasan los parámetros a una subrutina de Perl? Cuando depuré el siguiente código:

my $loopCounter = 1;
foreach(@authors) {

   my @splitAffiliations = splitAffiliations($params);
   my @foundItems = findAffiliationForAuthor($_, @splitAffiliations, $loopCounter);

   # Process @foundItems

   $loopCounter++;
}

...

sub findAffiliationForAuthor {

   my ($author, @affiliations, $aIndex) = @_;

   ...
} 

Encontré que la variable $loopCounter tenía un valor inmediatamente antes de que se llamara a la subrutina findAffiliationForAuthor, pero no estaba definida después de la llamada. Entonces, la subrutina recibió valores para los dos primeros parámetros y nada para el tercero. Pero, cuando cambié el orden de los parámetros a:

my @foundItems = findAffiliationForAuthor($loopCounter, $_, @splitAffiliations);

El valor de $loopCounter se retuvo y pasó la subrutina como se esperaba.

Parece que tengo que poner todas mis variables escalares antes de mis variables de matriz, o tal vez no mezclarlas. ¿Eso suena bien?

1
craigcaulfield 1 feb. 2015 a las 05:30

2 respuestas

La mejor respuesta

Ciertamente, el orden importa.

Los argumentos se pasan en el orden en que los pasa y un argumento de matriz se aplana en la lista de argumentos. La lista de argumentos aparece dentro de la subrutina como el contenido de la lista @_.

En realidad, no puede pasar una matriz como argumento; sus elementos se extraen y se introducen en la lista con cualquier otro argumento.

El problema que tiene se debe a la forma en que está procesando los argumentos:

my ($author, @affiliations, $aIndex) = @_;

$author obtiene el primer elemento de @_, como pretendías, pero @affiliations absorbe todo el resto de la lista. Luego, el valor undef se almacena en $aIndex.

Puede pasar una matriz única a una subrutina siempre que sea el último argumento:

my($first_scalar, $second_scalar, @array) = @_;

Si pasa varias matrices a una subrutina:

foo(@array1, @array2);

Los elementos de ambas matrices se aplanan en una sola lista, y no hay forma de que la subrutina sepa qué elementos provienen de qué argumento de matriz.

Puede pasar referencias a matrices:

sub foo {
    my ($scalar1, $array_ref1, $scalar2, $array_ref2) = @_;
    # ...
}

Y luego lo llaman así:

foo(42, \@array1, $some_scalar, \@array2);
5
Keith Thompson 1 feb. 2015 a las 03:00

Las subrutinas toman una lista de escalares como argumentos. Si crea la lista de argumentos a partir de una matriz, se pasará el contenido de la matriz.

$ perl -E'sub f { say "$_: $_[$_]" for 0..$#_; }  f("a", "b", "c", "d", "e")'
0: a
1: b
2: c
3: d
4: e

$ perl -E'sub f { say "$_: $_[$_]" for 0..$#_; }  @a = ("b"); f("a", @a, "c", "d", "e")'
0: a
1: b
2: c
3: d
4: e

$ perl -E'sub f { say "$_: $_[$_]" for 0..$#_; }  @a = ("b", "c"); f("a", @a, "d", "e")'
0: a
1: b
2: c
3: d
4: e

Ahora asigna la lista de argumentos (el contenido de @_) a

($author, @affiliations, $aIndex)

¿Cuántos escalares debería asignar a @affiliations? Podrías decir todo menos el primero y el último, pero luego tienes que proponer una nueva regla para

my (@a, @b) = @_;

Para mantenerlo simple, Perl siempre asigna todos los escalares restantes al primer arreglo de la lista. Esto funciona bien si la matriz es el último elemento, pero no de otra manera.

Si desea pasar una matriz a un sub, la mejor manera es pasarle una referencia.

$ perl -E'sub f { say "$_: $_[$_]" for 0..$#_; }  @a = ("b", "c"); f("a", \@a, "d", "e")'
0: a
1: ARRAY(0x14ff8d0)
2: d
3: e
2
ikegami 1 feb. 2015 a las 22:04