Una vez intenté escribir sobre esto, pero al final me di por vencido, ya que las reglas son algo difusas. Básicamente, tendrás que acostumbrarte.
Quizás sea mejor concentrarse en dónde las llaves y los paréntesis se pueden usar indistintamente: al pasar parámetros a llamadas a métodos. Usted puede sustituir el paréntesis con llaves si, y sólo si, el método espera un solo parámetro. Por ejemplo:
List(1, 2, 3).reduceLeft{_ + _} // valid, single Function2[Int,Int] parameter
List{1, 2, 3}.reduceLeft(_ + _) // invalid, A* vararg parameter
Sin embargo, hay más que necesita saber para comprender mejor estas reglas.
Mayor verificación de compilación con parens
Los autores de Spray recomiendan parens redondos porque brindan una mayor verificación de compilación. Esto es especialmente importante para DSL como Spray. Al usar parens le está diciendo al compilador que solo se le debe dar una sola línea; por lo tanto, si accidentalmente le da dos o más, se quejará. Ahora, este no es el caso con las llaves: si, por ejemplo, olvida a un operador en algún lugar, su código se compilará y obtendrá resultados inesperados y, potencialmente, un error muy difícil de encontrar. A continuación se inventa (ya que las expresiones son puras y al menos darán una advertencia), pero hace el punto:
method {
1 +
2
3
}
method(
1 +
2
3
)
El primero compila, el segundo da error: ')' expected but integer literal found
. El autor quería escribir 1 + 2 + 3
.
Se podría argumentar que es similar para los métodos de parámetros múltiples con argumentos predeterminados; Es imposible olvidar accidentalmente una coma para separar los parámetros cuando se usan parens.
Verbosidad
Una nota importante a menudo pasada por alto sobre la verbosidad. El uso de llaves se lleva inevitablemente a un código detallado, ya que la guía de estilo Scala establece claramente que el cierre de llaves debe estar en su propia línea:
... la llave de cierre está en su propia línea inmediatamente después de la última línea de la función.
Muchos reformateadores automáticos, como en IntelliJ, realizarán automáticamente este reformateo por usted. Por lo tanto, trate de usar parens redondos cuando pueda.
Notación de infijo
Al usar la notación infija, como List(1,2,3) indexOf (2)
puede omitir paréntesis si solo hay un parámetro y escribirlo como List(1, 2, 3) indexOf 2
. Este no es el caso de la notación de puntos.
Tenga en cuenta también que cuando tiene un único parámetro que es una expresión de múltiples tokens, como x + 2
o a => a % 2 == 0
, debe usar paréntesis para indicar los límites de la expresión.
Tuplas
Debido a que a veces puede omitir paréntesis, a veces una tupla necesita paréntesis adicionales como en ((1, 2))
, y a veces el paréntesis externo puede omitirse, como en (1, 2)
. Esto puede causar confusión.
Literales de función / función parcial con case
Scala tiene una sintaxis para funciones y literales de funciones parciales. Se parece a esto:
{
case pattern if guard => statements
case pattern => statements
}
Los únicos otros lugares donde puede usar case
declaraciones son con las palabras clave match
y catch
:
object match {
case pattern if guard => statements
case pattern => statements
}
try {
block
} catch {
case pattern if guard => statements
case pattern => statements
} finally {
block
}
No puede usar case
declaraciones en ningún otro contexto . Entonces, si quieres usar case
, necesitas llaves. En caso de que se pregunte qué hace que la distinción entre una función y una función parcial sea literal, la respuesta es: contexto. Si Scala espera una función, una función que obtienes. Si espera una función parcial, obtienes una función parcial. Si se esperan ambos, da un error sobre la ambigüedad.
Expresiones y Bloques
El paréntesis se puede usar para hacer subexpresiones. Las llaves se pueden usar para hacer bloques de código (esta no es una función literal, así que tenga cuidado de intentar usarla como tal). Un bloque de código consta de varias declaraciones, cada una de las cuales puede ser una declaración de importación, una declaración o una expresión. Dice así:
{
import stuff._
statement ; // ; optional at the end of the line
statement ; statement // not optional here
var x = 0 // declaration
while (x < 10) { x += 1 } // stuff
(x % 5) + 1 // expression
}
( expression )
Entonces, si necesita declaraciones, declaraciones múltiples, import
o algo así, necesita llaves. Y debido a que una expresión es una declaración, los paréntesis pueden aparecer dentro de llaves. Pero lo interesante es que los bloques de código también son expresiones, por lo que puede usarlos en cualquier lugar dentro de una expresión:
( { var x = 0; while (x < 10) { x += 1}; x } % 5) + 1
Entonces, dado que las expresiones son declaraciones y los bloques de códigos son expresiones, todo lo siguiente es válido:
1 // literal
(1) // expression
{1} // block of code
({1}) // expression with a block of code
{(1)} // block of code with an expression
({(1)}) // you get the drift...
Donde no son intercambiables
Básicamente, no se puede reemplazar {}
con ()
o viceversa en cualquier otro lugar. Por ejemplo:
while (x < 10) { x += 1 }
Esta no es una llamada al método, por lo que no puede escribirla de ninguna otra manera. Bueno, puedes poner llaves dentro del paréntesis para el condition
, así como usar paréntesis dentro de las llaves para el bloque de código:
while ({x < 10}) { (x += 1) }
Entonces, espero que esto ayude.