2012-01-12 33 views
12

En mi código, estoy estado usando el método bastante primitiva de parámetros de extracción a partir de una llamada a la función de la siguiente manera:¿Cómo se obtienen múltiples argumentos en las funciones de Perl?

sub addSix ($$$$$$) { 
    my ($a, $b, $c, $d, $e, $f) = (shift, shift, shift, shift, shift, shift); 
    return $a + $b + $c + $d + $e + $f; 
} 

print addSix (1, 2, 3, 4, 5, 6) . "\n"; 

(olvida el código primitivo, el bit saliente es el múltiplo shift llamadas).

Ahora que parece bastante complicado para mí y aunque Perl puede tener algo como:

my ($a, $b, $c, $d, $e, $f) = shift (6); 

o algo similar.

Pero no puedo encontrar nada como eso. Sé que puedo usar matrices para esto, pero creo que todavía tendría que descomprimir la matriz en escalares individuales. Eso no sería tan malo para el caso de ejemplo anterior, donde los seis parámetros son similares, pero estoy más interesado en el caso en que no son realmente adecuados como una matriz.

¿Cómo se pueden extraer los parámetros sin terminar con un marasmo de shift palabras clave?

+0

Nota: Evitar el uso de '' $ a' y $ b' como nombres de variables, ya que están pensados ​​para ser utilizados en el interior 'sólo bloquea sort'. – Zaid

+0

@Zaid, es el código _sample_, de hecho nombro mis variables reales un poco menos sucinto que eso :-) – paxdiablo

+2

obviamente no para un ejemplo de agregar, pero para una subrutina real que requiere más que un puñado de argumentos, podría ser mejor comience a usar parámetros con nombre: 'my% params = @_;' y llámelo como 'mysub foo => 1, bar => 2, baz => 3, ...' –

Respuesta

28

Usted puede simplemente escribir:

my ($a, $b, $c, $d, $e, $f) = (@_); 

Si no tuviera ese prototipo, y si ese sub fue llamado con más de seis argumentos, los que después de la sexta son simplemente "no se corresponde", $f se establecería en el sexto argumento.

Si quiere ver todos los argumentos después del sexto, puede hacerlo así.

my ($a, $b, $c, $d, $e, $f, @others) = (@_); 

Si su lista de escalares es más larga que la lista en el lado derecho, los últimos elementos serán undef.

+0

D'Oh. En el caso de pasar accidentalmente diez parámetros, ¿'$ f' será el sexto, o una combinación de seis a diez de alguna manera? ¿O el '$$$$$$' evitará pasar diez? ... No importa, tu edición "en los primeros cuatro minutos" lo aclaró. – paxdiablo

+1

El prototipo evita pasar más de seis argumentos. Si no tiene el prototipo de lista de argumentos (para que pueda pasar nada), '$ f' seguirá siendo el sexto argumento, el resto de la lista de argumentos simplemente no se" emparejará ". – Mat

+7

No hay necesidad de '()' alrededor de '@ _' – Zaid

7

El uso de prototipos es altamente desaconsejable a menos que haya un real necesario para ello.

Como siempre con Perl, hay más de una forma de hacerlo.

Aquí es una manera de garantizar la adición de sólo los primeros seis parámetros que se pasan:

use List::Util 'sum'; 

sub addSix { sum @_[0..5] } 

O si lo desea código de auto-documentado:

sub addSix { 

    my @firstSix = @_[0..5]; # Copy first six elements of @_ 
    return sum @firstSix; 
} 
+1

¿Por qué se desaconseja el prototipo? Pensé que eran invaluables para detectar casos en los que desearas un número fijo de params. – paxdiablo

+1

@paxdiablo: Lo referiré a [alguna lectura ligera] (http://stackoverflow.com/q/297034/133939). Y [luego algunos] (http://stackoverflow.com/q/3991143/133939). – Zaid

+2

@paxdiablo: ['" Los prototipos no son para la validación de argumentos "'] (http://stackoverflow.com/a/3991173/133939) – Zaid

3

Sé que esto es un hilo de edad, pero me hizo pensar en una mejor manera de cambiar valores múltiples. Todo esto es solo un poco divertido ... Publicando principalmente esto con fines educativos.

Claro, ($x, $y) = @_ es genial si quiere retener @_, pero quizás quiera cambiar sus argumentos por alguna razón? Quizás desee alguna funcionalidad de subrutina adicional determinada por la cantidad de argumentos restantes en @_.

La forma más limpia de una sola línea de lo que podía pensar de hacerlo es con un simple mapa

sub shiftySub { 
    map { $_ = shift } my ($v, $w, $x, $y); 
    # @_ now has up to 4 items removed 
    if (@_) { ... } # do stuff if arguments remain 
} 
  • Si se proporcionan argumentos 4, @_ es ahora vacío en el ámbito sub.
  • Si se proporcionan 5 argumentos, @_ tiene 1 elemento restante en el ámbito secundario.
  • Si se proporcionan 3 argumentos, @_ está vacío, y $y es undef en el alcance secundario.

En cuanto paxdiablo 's shift(6) operador teórico, podríamos crear nuestra propia función que realiza esta operación ...

sub shifter (\@;$) { 
    my ($array, $n) = (@_, 1); 
    splice(@$array, 0, $n); 
} 

La función se activa mediante la aplicación de un prototipo pase por ref (una de las razones muy limitadas por las que debe usar prototipos) para asegurarse de que la matriz se cambie en el alcance de la llamada. A continuación se usa simplemente como esto ...

my @items = ('one', 'two', 'three', 'four'); 
my ($x, $y) = shifter(@items, 2); 
# or as a replacement for shift 
my $z = shifter(@items) 
# @items has 1 item remaining in this scope! 

Por supuesto, también se puede utilizar esta función shifter dentro de sus otros submarinos. La desventaja principal de una función como esta es que debe realizar un seguimiento del número de asignaciones en ambos lados del operador.

espero my $post = 'informative' || 'interesting';

+0

No '||', pero de hecho '&&'! ;) – cxw

Cuestiones relacionadas