2012-08-10 21 views
10

Soy un practicante principiante en Scala y vi una sintaxis diferente para llamar a un método. Algunos son agradables, como ignorar paréntesis para un método sin parámetros, o ignorar el punto como enScala - sintaxis de llamada al método

1 to 10 

pero algunos realmente me rompecabezas. por ejemplo:

breakable { ... } 

esto es simplemente una llamada a un método ¿no? ¿Puedo hacer eso también para más de un parámetro o un parámetro que no sea una función sin parámetros?

Gracias

+2

sí, es un cierre. estás pasando un bloque de código a un método. Tenga en cuenta que en Scala, puede usar {} en lugar de() para pasar parámetros únicos a los métodos – aishwarya

+0

¿Qué le molesta aquí? ¿Es el bloque de código (la parte '{...}') después del nombre del método o el hecho de que no prefijamos el método con un nombre de objeto/clase? – Nicolas

Respuesta

22

Hay dos formas estándar de métodos de llamada:

obj.method(params) // dot notation 
obj method (params) // operator notation 

lo anterior se puede modificado de las siguientes maneras:

  1. Si params es un parámetro único, puede reemplazar () con {}.
  2. Si params es un solo parámetro y está utilizando notación de operador, puede soltar el paréntesis.
  3. Si method no toma los parámetros, puede soltar (params) (es decir, soltar el () vacío).
  4. Si method termina con :, entonces realmente se une a la derecha en la notación de operador. Es decir, (params) method_: obj es equivalente a obj.method_:(params).
  5. De cualquier forma, los espacios son opcionales siempre y cuando los identificadores se puedan diferenciar. Entonces uno puede agregar espacios a la notación de puntos, como obj . method (params) o escribir .method(params) en la siguiente línea, como sucede a menudo con el encadenamiento de llamadas, así como eliminar espacios de la notación del operador, como en a+b.

También hay algunas cosas con inferencia de tupla, pero trato de evitarlo, así que no estoy seguro de las reglas exactas.

Sin embargo, ninguno de estos explicará el ejemplo del que está confundido.Antes de explicar que, sin embargo, me gustaría mostrar algunos azúcares sintácticas que también pueden ser utilizados para llamar a métodos:

obj(params) // equivalent to obj.apply(params) 
obj.x = y // equivalent to obj.x_=(y), if obj.x also exists 
obj(x) = y // equivalent to obj.update(x, y) 
obj op= y // equivalent to obj = obj op y, if op is symbolic 
~obj  // equivalent to obj.unary_~; also for !, + and -, but no other symbol 

Ok, ahora al ejemplo que diste. Uno puede importar miembros de valores estables. Java puede hacerlo para métodos estáticos con su importación estática, pero Scala tiene un mecanismo más general: la importación desde paquetes, objetos o instancias comunes no es diferente: trae miembros de tipo y miembros de valor. Los métodos caen en la última categoría.

Entonces, imagine que tiene val a = 2, y lo hace import a._. Eso pondrá en alcance todos los métodos Int, para que pueda llamarlos directamente. No se puede hacer +(2), porque eso sería interpretado como un llamado a unary_+, pero que se podría llamar *(4), por ejemplo:

scala> val a = 2 
a: Int = 2 

scala> import a._ 
import a._ 

scala> *(4) 
res16: Int = 8 

Ahora, aquí es la regla. Puede llamar

method(params) 

Si:

  1. method se ha importado a su alcance.
  2. se mantiene el paréntesis (incluso si sólo hay un parámetro)

Tenga en cuenta que hay un problema de prioridad también. Si escribe obj method(params), Scala asumirá que method pertenece a obj, incluso si se importó al alcance.

+0

Gran respuesta. Solo tengo una pregunta sobre su punto número 1, sobre poder llamar a un método con notación {} en lugar de(). ¿Hay alguna razón específica por la cual esta sintaxis está disponible? Esta sintaxis parece ser utilizada comúnmente en muchos marcos y sus ejemplos documentados. Me pregunto si esta sintaxis particular es compatible por una razón funcional muy específica. ¿Se usa generalmente al pasar cierres como argumentos para una función? Me gustaría entender sus raíces para poder comprender y razonar al respecto con claridad. Gracias. – HiChews123

+2

@ acspd7 Bueno, '()' y '{}' tienen diferentes significados dentro de _expression_. Es decir, '2 * (3 + 4)' y '2 * {3 + 4}' tienen el mismo resultado, pero son cosas diferentes. Solo puede poner expresiones dentro de un paréntesis, mientras que pone _definitions_ y _statements_ dentro de llaves, y el valor de la última instrucción es el valor de expresión de la misma (las llaves son, en sí mismas, una expresión). La razón por la cual 'f (...)' puede reemplazarse por 'f {...}' es solo para que la gente no tenga que escribir 'f ({...})'. Eso permite a las personas escribir estructuras de control de "usuario" que parecen nativas. –

15

Si desugar esto vamos a tener:

breakable({ ... }) 

Esto coincide con la firma

breakable: (op: ⇒ Unit): Unit 

y usos llamado así llamada por nombre argumentos (que puede pensar de esto como pasar un bloque de código como argumento)

Más sobre Scala le permite escribir esto:

scala> def foo (op1: => Unit)(op2: => Unit) = {op1;op2;} 
foo: (op1: => Unit)(op2: => Unit)Unit 

scala> foo { println(1) } { println(2) } 
1 
2 

Arriba está el ejemplo de la función curry

Cuestiones relacionadas