2010-08-22 17 views
11

He estado trabajando con Perl durante aproximadamente dos meses; simplemente se me ocurrió que no sé cómo establecer argumentos predeterminados para las subrutinas. Esto es lo que consideré:Valores de argumento predeterminados en las subrutinas

sub hello { 
    print @_ || "Hello world"; 
} 

Y eso funciona bien si todo lo que necesita era un argumento. ¿Cómo establecería valores predeterminados para múltiples argumentos? Iba a hacer esto:

sub hello { 
    my $say = $_[0] || "Hello"; 
    my $to = $_[1] || "World!"; 
    print "$say $to"; 
} 

Pero eso es mucho trabajo ... Debe haber una manera más fácil; posiblemente una mejor práctica? ¡Gracias!

Respuesta

2

Existe el módulo Attribute::Default en CPAN. Probablemente más limpio que esto, y evita un par de complejidades (por ejemplo, ¿qué pasa si desea pasar false a su subrutina?).

También he visto personas usar my $var = exists @_[0] ? shift : "Default_Value";, pero la documentación de Perl señala que calling exists on arrays is deprecated, así que realmente no lo recomendaría.

de fragmentos de Attribute::Default desde la página doc:

sub vitals : Default({age => 14, sex => 'male'}) { 
    my %vitals = @_; 
    print "I'm $vitals{'sex'}, $vitals{'age'} years old, and am from $vitals{'location'}\n"; 
    } 

    # Prints "I'm male, 14 years old, and am from Schenectady" 
    vitals(location => 'Schenectady'); 
11

por lo general hacer algo como:

sub hello { 
    my ($say,$to) = @_; 
    $say ||= "Hello"; 
    $to ||= "World!"; 
    print "$say $to\n"; 
} 

Tenga en cuenta que a partir de Perl 5.10, puede utilizar el operador "//=" para probar si la variable está definida, y no solo no es cero. (Imagine la llamada hello("0","friend"), que usar lo anterior produciría "Hello friend", que podría no ser lo que quería. Con el operador //= obtendría "0 friend").

+0

Sí me trataron 'impresión @_ // "Hola mundo",' 'pero me dio 0' ... – David

+3

@Davidmoreen: probar una matriz para definir no es útil – ysth

+3

@Davidmoreen, la forma correcta de decir que es 'print $ _ [0] //" Hello world ";'. Como ya dijo, no puede usar 'defined' en una matriz (que es lo que' // 'significa), porque una matriz en contexto escalar devuelve su longitud, que siempre está definida. – cjm

4

Como el mecanismo de Perl para pasar argumentos a subrutinas es una lista única, los argumentos son posicionales. Esto hace que sea difícil proporcionar valores predeterminados. Algunos integradores (por ejemplo, substr) manejan esto ordenando argumentos de acuerdo con la probabilidad de que se utilicen; los argumentos menos utilizados aparecen al final y tienen valores predeterminados útiles.

Una forma más limpia de hacerlo es mediante el uso de argumentos con nombre. Perl no admite argumentos con nombre per se, pero se puede emular con los hashes:

use 5.010; # for // 

sub hello { 
    my %arg = @_; 
    my $say = delete $arg{say} // 'Hello'; 
    my $to = delete $arg{to} // 'World!'; 
    print "$say $to\n"; 
} 

hello(say => 'Hi', to => 'everyone'); # Hi everyone 
hello(say => 'Hi');     # Hi world! 
hello(to => 'neighbor Bob');   # Hello neighbor Bob 
hello();        # Hello world! 

Nota: El // se añadió en Perl v5.10-o definido operador. Es más robusto que el uso de un lógico o (||) ya que no será el predeterminado en los valores lógicamente falsos '' y 0.

14

que lo hacen con argumentos con nombre, así:

sub hello { 
    my (%arg) = (
     'foo' => 'default_foo', 
     'bar' => 'default_bar', 
     @_ 
    ); 

} 

creo Params::Validate es compatible con los valores por defecto, pero eso es más problemas de los que me gusta tomar.

3

Si ve la documentación de Perl Best Practices: Valores Parámetros por defecto por Damian Conway a continuación, encontrará algunos puntos importantes como:

  • resolver los valores de cualquier argumento predeterminado tan pronto como @_ está desempaquetado.
  • Sugiere que si tiene que configurar muchos valores predeterminados, la forma más limpia sería descompensar los valores predeterminados de en tablas, es decir, un hash y luego preinicializar el hash de argumento con esa tabla.

Ejemplo:

#!/usr/bin/perl 
    use strict; 
    use warning; 
    my %myhash = (say => "Hello", to => "Stack Overflow"); 
    sub hello { 
    my ($say, $to) = @_; 
    $say = $say ? $say : $myhash{say}; 
    $to = $to ? $to : $myhash{to}; 
    print "$say $to\n"; 
    } 
    hello('Perl');  # output :Perl Stack Overflow 
    hello('','SO');  # output :Hello SO 
    hello('Perl','SO'); # output :Perl SO 
    hello();   # output :Hello Stack Overflow 

Para más detalle y ejemplo completo refieren Perl Best Practices.

4

También eche un vistazo a Method::Signatures. Esto usa Devel::Declare para proporcionar algo de azúcar adicional (¡necesario!) Con las palabras clave method y func.

A continuación se muestra el ejemplo usando el nuevo func:

use Method::Signatures; 

func hello ($say='Hello', $to='World!') { 
    say "$say $to"; 
} 

hello('Hello', 'you!'); # => "Hello you!" 
hello('Yo');    # => "Yo World!" 
hello();      # => "Hello World!" 

/I3az/

1

La mejor manera de abordar el problema han sido discutidos en las otras respuestas.
Una cosa que me llama la atención es que aunque usted afirma que:

sub hello { 
    print @_ || "Hello world"; 
} 

y que funciona muy bien para si todo lo que necesitaba era un argumento.

¿Has probado ese código? ¡Imprimirá el número de argumentos o, cuando no haya ninguno, Hello World!
La razón para esto es que el || -operator tiene prioridad y fuerza al lado izquierdo en el contexto escalar, reduciendo así @_ al número de argumentos que usted proporciona, ¡NO a los argumentos en sí!
eche un vistazo a perlop para obtener más información sobre los operadores en Perl.

HTH,
Paul

0

Para más azúcar, consulta Method::Signatures:

func add($this = 23, $that = 42) { 
    return $this + $that; 
} 
+0

Lo siento, no me di cuenta de que ya estaba propuesto – pwes

Cuestiones relacionadas