Regreso en Scala
Soy un programador novato en Scala y encontré un comportamiento extraño.
def balanceMain(elem: List[Char]): Boolean =
{
if (elem.isEmpty)
if (count == 0)
true;
else false;
if (elem.head == '(')
balanceMain(elem.tail, open, count + 1);....
Básicamente, quiero que vuelva a ser verdadero si elem.isEmpty
ycount == 0
. Otherwise, I want to return false.
Ahora arriba he leído que no es necesario agregar una declaración de devolución en Scala. Así que lo he omitido return
arriba. Pero no devuelve el valor booleano. Si agrego una declaración de devolución comoreturn true
. it works perfectly. Why is it so?
Además, ¿por qué se considera una mala práctica tener declaraciones de devolución en Scala?
No es tan sencillo como omitir la return
palabra clave. En Scala, si no hay return
, la última expresión se toma como el valor de retorno. Entonces, si la última expresión es lo que desea devolver, puede omitir la return
palabra clave. Pero si lo que desea devolver no es la última expresión, Scala no sabrá que desea devolverla .
Un ejemplo:
def f() = {
if (something)
"A"
else
"B"
}
Aquí la última expresión de la función f
es una expresión if/else que se evalúa como una cadena. Como no hay return
una marca explícita, Scala inferirá que desea devolver el resultado de esta expresión if/else: una cadena.
Ahora, si agregamos algo después de la expresión if/else:
def f() = {
if (something)
"A"
else
"B"
if (somethingElse)
1
else
2
}
Ahora la última expresión es una expresión if/else que se evalúa como Int. Entonces el tipo de retorno f
será Int. Si realmente queremos que devuelva el String, entonces estamos en problemas porque Scala no tiene idea de que eso es lo que pretendíamos. Por lo tanto, tenemos que solucionarlo almacenando la cadena en una variable y devolviéndola después de la segunda expresión if/else, o cambiando el orden para que la parte de la cadena suceda al final.
Finalmente, podemos evitar la return
palabra clave incluso con una expresión if-else anidada como la suya:
def f() = {
if(somethingFirst) {
if (something) // Last expression of `if` returns a String
"A"
else
"B"
}
else {
if (somethingElse)
1
else
2
"C" // Last expression of `else` returns a String
}
}
En realidad, este tema es un poco más complicado como se describe en las respuestas hasta ahora. Esta publicación de blog de Rob Norris lo explica con más detalle y brinda ejemplos sobre cuándo usar return realmente romperá su código (o al menos tendrá efectos no obvios).
Llegados a este punto, permítanme citar la esencia del post. La declaración más importante está justo al principio. Imprime esto como póster y colócalo en tu pared :-)
La
return
palabra clave no es “opcional” ni “inferida”; cambia el significado de su programa y nunca debe usarlo.
Da un ejemplo en el que realmente se rompe algo cuando se inserta una función
// Inline add and addR
def sum(ns: Int*): Int = ns.foldLeft(0)((n, m) => n + m) // inlined add
scala> sum(33, 42, 99)
res2: Int = 174 // alright
def sumR(ns: Int*): Int = ns.foldLeft(0)((n, m) => return n + m) // inlined addR
scala> sumR(33, 42, 99)
res3: Int = 33 // um.
porque
Una
return
expresión, cuando se evalúa, abandona el cálculo actual y regresa al llamador del método en el quereturn
aparece.
Este es sólo uno de los ejemplos que se dan en la publicación vinculada y es el más fácil de entender. Hay más y te recomiendo encarecidamente que vayas allí, leas y comprendas.
Cuando vienes de lenguajes imperativos como Java, esto puede parecer extraño al principio, pero una vez que te acostumbras a este estilo tendrá sentido. Permítanme cerrar con otra cita:
Si se encuentra en una situación en la que cree que quiere regresar antes, necesita repensar la forma en que definió su cálculo.
No programo Scala, pero uso otro lenguaje con retornos implícitos (Ruby). Tienes código después de tu if (elem.isEmpty)
bloque: la última línea de código es lo que se devuelve, razón por la cual no obtienes lo que esperabas.
EDITAR: Aquí también hay una forma más sencilla de escribir su función. Simplemente use el valor booleano de isEmpty y cuente para devolver verdadero o falso automáticamente:
def balanceMain(elem: List[Char]): Boolean =
{
elem.isEmpty && count == 0
}