2010-08-08 11 views

Respuesta

46

return; devolverá una lista vacía en contexto de lista pero undef en contexto escalar. return undef; siempre devolverá un solo valor undef incluso en el contexto de la lista.

En general, no suele ser una buena idea para return undef; de una subrutina que normalmente se utiliza en el contexto de lista:

sub foo { return undef } 
if (my @x = foo()) { 
    print "oops, we think we got a result"; 
} 

En general, no suele ser una buena idea para return; de una subrutina que normalmente se utiliza en contexto escalar , porque no se comportará como el usuario espera en el contexto de la lista:

sub foo { return } 
%x = ('foo' => foo(), 'bar' => 'baz'); 
if (! exists $x{'bar'}) { 
    print "oops, bar became a value, not a key"; 
} 

Ambos de estos errores ocurren un poco en la práctica, este último más aún, tal vez porque los submarinos que se espera que devolver un escalar son más común. Y si se espera que devuelva un escalar, es mejor que devuelva un escalar.

+0

En su segundo ejemplo, diría que la falla no fue la definición de foo, sino que tiene un sub en el lado derecho de una coma gruesa. En mi humilde opinión, es un estilo de programación frágil. – nslntmnx

+0

@nslntmnx: No tengo claro qué tiene que ver la coma grasa o qué harías en su lugar. ¿Puedes explicar? – ysth

+1

Todo esto se debe al hecho de que la coma de grasa * NO * fuerza el contexto escalar en el lado derecho. En mi humilde opinión, en el segundo ejemplo, la definición de sub foo es perfecta. La falla fue causada por el cuestionable estilo de codificación de tener una subllamada en el lado derecho de una coma gruesa. Tener una subllamada en el lado derecho (como lo ha mostrado) puede ocasionar la corrupción de las llaves/pares, por lo tanto, un estilo de codificación frágil. – nslntmnx

19

Dada

sub foo { return; } 
sub bar { return undef; } 

En contexto escalar, se comportan de la misma.

my $foo = foo(); # $foo is undef 
my $bar = bar(); # $bar is undef 

En el contexto de lista, se comportan de manera diferente

my @foo = foo(); # @foo is() (an empty list) 
my @bar = bar(); # @bar is (undef) (a one-element list) 

Tenga en cuenta que una lista de un solo elemento es un valor verdadero en contexto booleano, a pesar de que es el único elemento undef.

En general, generalmente no es una buena idea return undef; desde una subrutina, debido a su comportamiento en contexto.

+4

Es por esto que las "Mejores prácticas de Perl" (y 'Perl :: Critic') sugieren no usar' return undef'. – hillu

+6

@hillu: y es la misma razón por la que en algún momento es una buena idea usarlo. Por ejemplo, se supone que la función devuelve una respuesta lógica (booleana) y desea usarla otra función llamada 'foo (1, bar(), 2)'. Si 'bar' se escribiera con' return; ', se sorprenderá ;-) –

+5

Una de las más de unas pocas cosas PBP se equivoca. – ysth

2

Creo que todavía estoy de acuerdo con PBP.

1) Se debe evitar la función de anidación llama:

my $result = bar(); 
foo(1, $result, 2); 

2) Siempre debe ser explícita (cuando hacer las cosas "complicadas"):

foo(1, scalar bar(), 2); 
+0

1) No se trata solo de anidar llamadas a funciones. 2) Sí, desde la perspectiva de la persona que llama, eso sería algo bueno. Desde la perspectiva del llamado, no se debe contar. – ysth

+0

1) más ejemplos, ¿entonces? de todos modos, creo que terminaría con resultados erráticos con más frecuencia con $ perl -wle 'sub get_values ​​{return undef; }; my @values ​​= get_values; print escalar @values; ' Si quiere ser más explícito y correcto, siempre existe Contextual :: Return http://p3rl.org/Contextual::Return – nicomen

+3

su 'get_values' está destinado para su uso en el contexto de la lista, y como tal debería ser _not_ 'return undef'. Pero si tuvieras una función 'get_value' que devolviera un escalar, _siempre_ devolvería un escalar, nunca una lista vacía, por lo que usaría' return undef'. Ver la respuesta de ysth. – cjm

2

el libro "Perl Best Practices" recomienda el uso de return; en lugar de return undef; porque este último devolverá una lista de un elemento en el contexto de la lista (las otras respuestas ya lo mencionan). Esto sería un "error desagradable" según el libro.

Sin embargo, creo que devolver nada realmente puede causar errores serios (probablemente difíciles de encontrar), mientras que llamar a una función booleana en contexto de lista parece bastante simple de depurar.

Así que siempre retorno algo (que evalúa a) falso en mis funciones booleanas (normalmente 0 para falso y 1 para el verdadero).
(Sí, esto también podría devolver una lista de un solo elemento en el contexto de la lista - por lo que el comentario en el libro es técnicamente correcto -., Pero entonces el error real sería llamar a la función booleana en el contexto de la lista)

Para ser claro, todavía recomiendo el libro. Ofrece muchos buenos consejos.
Y me refiero al Capítulo 9 (Subprogramas), página 199/200 ("Utilizar un retorno simple para devolver la falla") en el libro "Mejores prácticas de Perl" por Damian Conway (O'Reilly Media, Inc.), ISBN 978-0-596-00173-5. No estoy seguro si hay otra/nueva edición.

Nota al margen:
Perl parece devolver una cadena vacía al negar algo. my $foo = 5; return !$foo; devuelve q().

+1

'! $ Foo' es la cadena vacía porque Perl usa 1 para verdadero y la cadena vacía para falso. Debido al '!', Estás en un contexto booleano. –

+0

No, '! 5' es el valor falso canónico, que es "" en contexto de cadena y 0 en contexto numérico. – ysth

Cuestiones relacionadas