2012-09-24 27 views
48

Soy un programador de scala novato y encontré un comportamiento extraño.Devolución en Scala

def balanceMain(elem: List[Char]): Boolean = 
    { 
    if (elem.isEmpty) 
     if (count == 0) 
     true; 
     else false; 

    if (elem.head == '(') 
     balanceMain(elem.tail, open, count + 1);.... 

encima básicamente quiero volver cierto si elem.isEmpty y count == 0. De lo contrario, quiero devolver falso.

Ahora arriba he leído que no hay necesidad de agregar una declaración de devolución en scala. Así que 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?

También, Por qué se considera una mala práctica tener sentencias de retorno en Scala

+1

** por lo general ** no se necesita la palabra clave return, siempre que divida el código en métodos suficientemente pequeños. – mauhiz

+0

@mauhiz Gracias. ¿Puedes por favor explicarlo? Como lo haras. – Jatin

+2

parece que está tomando el curso de coursera scala. todo lo mejor :) – weima

Respuesta

90

No es tan simple como la omisión de la palabra clave return. En Scala, si no hay return, entonces la última expresión se toma como el valor de retorno. Por lo tanto, si la última expresión es la que desea devolver, puede omitir la palabra clave return. Pero si lo que desea devolver es no la última expresión, entonces Scala no sabrá que desea devolverlo.

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 una marca explícita return, Scala deducirá que desea devolver el resultado de esta expresión if/else: una Cadena.

Ahora, si añadimos algo después de la si/expresión más:

def f() = { 
    if (something) 
    "A" 
    else 
    "B" 

    if (somethingElse) 
    1 
    else 
    2 
} 

Ahora la última expresión es una expresión si otra cosa/que se evalúa como un Int. Entonces, el tipo de retorno de f será Int. Si realmente queremos que devuelva el String, entonces estamos en problemas porque Scala tiene sin idea que eso es lo que pretendíamos. Por lo tanto, debemos solucionarlo almacenando el String en una variable y devolviéndola después de la segunda expresión if/else, o cambiando el orden para que la parte String pase la última.

Por último, podemos evitar la palabra clave return incluso con una expresión anidada if-else 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 
    } 

}

+1

Por todos los dioses, ¡gracias! Estuve peleando con el mismo problema durante horas (también hice el curso en Coursera) y no pude entender por qué era necesaria la devolución. –

+0

para el primer ejemplo, qué pasa si agrega devoluciones. i.e 'return" A "' and 'return" B "'? –

+0

@ T.Rex devolvería a la persona que llama de f() con el valor "A" o "B".Pero como expliqué en mi respuesta. Nunca use return en Scala. Si las declaraciones en Scala funcionan de una manera funcional. Evalúan algo con un tipo. Al igual que el operador ternario en Java (? :). Ejemplo: val foo = if (mybool) "A" else "B" - foo será una Cadena que contenga "A" o "B". Del mismo modo, piense en una función que no devuelve algo, sino que evalúa el valor de la última expresión en ella. – Grmpfhmbl

3

No programo Scala, pero utilizar otro idioma con rendimiento, implícito (rubí). Tiene código después de su bloque if (elem.isEmpty): la última línea de código es la que se devuelve, por lo que no está obteniendo lo que esperaba.

EDITAR: Esta es una forma más sencilla de escribir su función también. Sólo tiene que utilizar el valor booleano de estaVacia y contar para volver verdadero o falso automáticamente:

def balanceMain(elem: List[Char]): Boolean = 
{ 
    elem.isEmpty && count == 0 
} 
+0

Gracias. Pero solo quiero volver si elem.isEmpty && count == 0 devuelve true; de ​​lo contrario, continúa el bloque. Lo anterior volverá incluso si es falso. – Jatin

+0

@Jatin: Ah, no me di cuenta. La devolución temprana y "explícita" sería apropiada en este caso. – jmdeldin

+0

@Frank: Tampoco está definido en el código del OP. Supuse que era una llamada a un método. – jmdeldin

4

Por defecto se le devolverá la última expresión de una función. En su ejemplo, hay otra expresión después del punto, donde quiere que su valor de retorno. Si desea devolver algo antes de su última expresión, igual debe usar return.

podrá modificar su ejemplo como este, para devolver un Boolean de la primera parte

def 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 
    } 
} 
+9

No "declaración". "expresión" –

+1

@ViktorKlang, gracias por la pista, la corrigió. – Tharabas

3

No escriba if declaraciones sin la correspondiente else. Una vez que agregue el else a su fragmento, verá que su true y false 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.... 
+1

Lo apliqué, obtuve 3 IF anidados y se ve feo. ¿Hay algún patrón para que se vea mejor? – Sergey

9

Este tema es en realidad un poco más complicado como se describe en las respuestas hasta el momento. Este blogpost by Rob Norris lo explica con más detalle y brinda ejemplos sobre cuándo utilizar el retorno 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 es correcta al principio. Imprima esto como un póster y colóquelo en su muro :-)

La palabra clave return no es "opcional" o "inferida"; cambia el significado de su programa , y nunca debe usarlo.

Se da un ejemplo, en que incluso se rompe algo, cuando inline 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

Un return expresión, cuando se evalúa, abandona el cómputo actual y vuelve a la persona que llama del método en el que aparece return.

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 te animo a ir, leer y entender.

Cuando venga 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:

Si se encuentra en una situación en la que piensa que quiere regresar temprano, necesita volver a pensar la forma en que ha definido su cálculo.

+1

No estoy de acuerdo con Rob, IMO no debe usar 'return' solo en expresiones lambda, pero esta es una opción de diseño de mierda en el lenguaje, el código ni siquiera debería compilarse (en python esto se evita teniendo' lambda' palabra clave sin declaración de devolución) ... en cada uno de los casos no veo un problema real al usar 'return' si desea devolver un valor (y sí salir de la ejecución del método porque es para lo que se usa return en todos los idiomas !) – daveoncode

+0

Eres libre de tener tu opinión, pero muchas personas están de acuerdo en que usar devoluciones en Scala es, al menos, un mal estilo. Te reto a que encuentres ejemplos oficiales de doc Scala que utilicen return. Es AFAIK ni siquiera explicado en los documentos oficiales, solo en el documento de especificaciones (capítulo 6.20). Para citar al propio Martin Odersky (Programación en Scala) "El estilo recomendado para los métodos es, de hecho, evitar declaraciones explícitas y especialmente múltiples. En cambio, piense en cada método como una expresión que arroja un valor, que se devuelve". La primera edición de este libro está disponible en línea gratis http://www.artima.com/pins1ed/ – Grmpfhmbl

Cuestiones relacionadas