Soy un programador novato en Scala y me encontré con 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 volver verdadero si elem.isEmpty
y count == 0
. De lo contrario, quiero devolver falso.
Ahora, arriba, he leído que no es necesario agregar una declaración de devolución en scala. Por eso lo he omitido return
arriba. Pero no devuelve el booleano. Si agrego una declaración de devolución como return true
. funciona perfectamente. ¿Por que es esto entonces?
Además, ¿por qué se considera una mala práctica tener declaraciones de retorno en scala?
Respuestas:
No es tan simple como simplemente omitir la
return
palabra clave. En Scala, si no hayreturn
, se toma la última expresión como valor de retorno. Entonces, si la última expresión es lo que desea devolver, puede omitir lareturn
palabra clave. Pero si lo que desea devolver no es la última expresión, Scala no sabrá que quería 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 String. Como no hay unareturn
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 de
f
será Int. Si realmente quisiéramos que devolviera el String, entonces tenemos problemas porque Scala no tiene idea de que eso es lo que pretendíamos. Por lo tanto, tenemos que arreglarlo 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 ocurra 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 }
}
fuente
return "A"
yreturn "B"
?Este tema es en realidad 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 ofrece ejemplos sobre cuándo el uso de return realmente romperá su código (o al menos tendrá efectos no obvios).
En este punto, permítanme citar la esencia de la publicación. La declaración más importante está al principio. Imprime esto como un póster y colócalo en tu pared :-)
Da un ejemplo, donde realmente rompe algo, cuando 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
Este es solo 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 les animo mucho a que vayan allí, lean y comprendan.
Cuando viene de lenguajes imperativos como Java, esto puede parecer extraño al principio, pero una vez que se acostumbre a este estilo, tendrá sentido. Permítanme cerrar con otra cita:
fuente
return
solo en expresiones lambda, pero esta es una elección de diseño de mierda en el lenguaje, el código ni siquiera debería compilarse (en Python esto se evita al tener unalambda
palabra clave sin la declaración de retorno). .. en cada otro caso, no veo un problema real en el usoreturn
si desea devolver un valor (y sí, salir de la ejecución del método porque es para lo que se usa el retorno en todos los idiomas)No programo Scala, pero uso otro lenguaje con retornos implícitos (Ruby). Tiene código después de su
if (elem.isEmpty)
bloque: la última línea de código es lo que se devuelve, por lo que no obtiene lo que espera.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 }
fuente
explicit
En este caso, sería apropiado regresar temprano y entonces.No escriba
if
declaraciones sin su correspondienteelse
. Una vez que agregue elelse
a su fragmento, verá que sutrue
yfalse
son de hecho las últimas expresiones de la función.def balanceMain(elem: List[Char]): Boolean = { if (elem.isEmpty) if (count == 0) true else false else if (elem.head == '(') balanceMain(elem.tail, open, count + 1) else....
fuente
De forma predeterminada, se devolverá la última expresión de una función. En su ejemplo, hay otra expresión después del punto, donde desea su valor de retorno. Si desea devolver algo antes de su última expresión, aún debe usar
return
.Puede modificar su ejemplo de esta manera, para devolver un
Boolean
de la primera partedef balanceMain(elem: List[Char]): Boolean = { if (elem.isEmpty) { // == is a Boolean resulting function as well, so your can write it this way count == 0 } else { // keep the rest in this block, the last value will be returned as well if (elem.head == "(") { balanceMain(elem.tail, open, count + 1) } // some more statements ... // just don't forget your Boolean in the end someBoolExpression } }
fuente
Utilice la coincidencia de casos para fines de devolución anticipada. Te obligará a declarar todas las ramas de retorno explícitamente, evitando el error descuidado de olvidar escribir return en alguna parte.
fuente