Función multilínea literal como argumentos en Scala

Siempre me pregunté por qué, a veces, con los literales de funciones, podemos ignorar el corsé incluso para varias declaraciones. Para ilustrar esto, la syntax para un literal de función multilínea es encerrar las declaraciones con llaves. Al igual que,

val fl = (x: Int) => { println("Add 25 to "+x) x + 25 } 

Sin embargo, cuando lo pasa a una función de argumento único, puede ignorar el corsé requerido para el literal de la función.

Entonces para una función dada f,

 def f( fl: Int => Int ) { println("Result is "+ fl(5)) } 

Puedes llamar a f () así,

 f( x=> { println("Add 25 to "+x) x + 25 }) ------------------------- Add 25 to 5 Result: 30 

O cuando usa llaves en lugar de paréntesis en la llamada a la función, puede quitar las llaves internas del literal de la función. Entonces el siguiente código también funcionará

 f{ x=> println("Add 25 to "+x) x + 25 } 

El código anterior es más legible y observo que muchos ejemplos usan esta syntax. Sin embargo, ¿hay alguna regla especial que me haya pasado por alto, explicar por qué esto funciona según lo previsto?

Solo hay un par de reglas simples de syntax. El apéndice de la especificación vale la pena examinarlo.

Una función literal o anónima función (6.23) se verá como x => Expr o x => Block según si el contexto es un Expr o un ResultExpr, respectivamente.

Una aplicación de función (6.6) se verá como f(Expr, Expr) o f BlockExpr , es decir, f{ Block } . Es decir, un BlockExpr es solo una secuencia de sentencias de bloque dentro de {...} .

Cuando llame a f(g) , entonces g es un Expr, entonces como un literal de función, x => Expr . El Expr puede ser un BlockExpr, x => { ... } .

Cuando llamas a f{ Block } , entonces f { x => ... } tiene la función literal en ResultExpr de un bloque (que es solo una secuencia de enunciados, no se requieren llaves).

Aquí, es obvio que el anon func está en la parte inferior de un bloque:

 scala> def m(x: Int=>Int) = x(5) m: (x: Int => Int)Int scala> m { | val y = 7 | x => // no brace | x+y+1 | } res0: Int = 13 

Esta es una de las cosas que hacen que Scala sea hermosa para mí.

La respuesta simple a tu pregunta es:

Los paréntesis () están destinados a construcciones de una sola línea. Por ejemplo, esto funciona:

  def f(fl: Int => Int) { println("Result is " + fl(5)) } f( x => x + 25) f(x => x + 25) // single line 

y llaves {} están destinadas a declaraciones de líneas múltiples. Por ejemplo, esto funciona:

  f { x => println("Add 25 to " + x) x + 25 } 

pero este código no funciona:

 f ( x => println("Add 25 to " + x) x + 25 ) 

El comstackdor se queja con el siguiente mensaje:

el valor x no es un miembro de la causa posible de la unidad: tal vez falta un punto y coma antes de `valor x ‘?

Si agrega el punto y coma, obtendrá un error de syntax causado por el paréntesis no coincidente.

Si intenta hacer esto:

 f { x => println("Add 25 to " + x) x + 25 } 

El comstackdor te responderá con el mensaje:

 value x is not a member of unit 

¿Entiende que está tratando de encontrar a x como miembro de la unidad? Me gusta:

 f { println("Add 25 to " + x).x.+(25) } 

Lo cual está claramente mal.

Si agrega las llaves, como esta:

 f ( x => { println("Add 25 to " + x) x + 25 } ) 

Esto también funcionará, pero aún tiene una statement de líneas múltiples que se señala mediante el uso de llaves. Entonces el comstackdor sabe lo que quiere allí para imprimir primero y luego agregar 25 a x.

He sido mordido antes por esas sutilezas. Desde entonces, he estado prestando atención a la forma en que codifico con esos, porque codificarás y leerás mucho de esto cuando uses mapas, flatmaps, foreachs, fors y currying principalmente.

¡Aclamaciones!

Intereting Posts