Regreso en Scala

Resuelto Jatin asked hace 12 años • 6 respuestas

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.isEmptyycount == 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 returnarriba. 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?

Jatin avatar Sep 24 '12 14:09 Jatin
Aceptado

No es tan sencillo como omitir la returnpalabra 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 returnpalabra 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 fes una expresión if/else que se evalúa como una cadena. Como no hay returnuna 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 fserá 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 returnpalabra 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
  }

}

dhg avatar Sep 24 '2012 07:09 dhg

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 returnpalabra 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 returnexpresión, cuando se evalúa, abandona el cálculo actual y regresa al llamador del método en el que returnaparece.

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.

Grmpfhmbl avatar Aug 17 '2016 10:08 Grmpfhmbl

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
}
jmdeldin avatar Sep 24 '2012 07:09 jmdeldin