La sintaxis de Scala tiene muchos símbolos. Dado que este tipo de nombres son difíciles de encontrar utilizando los motores de búsqueda, sería útil una lista completa de ellos.
¿Cuáles son todos los símbolos en Scala y qué hace cada uno de ellos?
En particular, me gustaría saber acerca de ->
, ||=
, ++=
, <=
, _._
, ::
, y :+=
.
Respuestas:
Divido a los operadores, con el propósito de enseñar, en cuatro categorías :
Es una suerte, entonces, que la mayoría de las categorías estén representadas en la pregunta:
El significado exacto de la mayoría de estos métodos depende de la clase que los define. Por ejemplo,
<=
onInt
significa "menor o igual que" . El primero,->
daré como ejemplo a continuación.::
es probablemente el método definido enList
(aunque podría ser el objeto del mismo nombre), y:+=
es probablemente el método definido en variasBuffer
clases.Entonces, vamos a verlos.
Palabras clave / símbolos reservados
Hay algunos símbolos en Scala que son especiales. Dos de ellas se consideran palabras clave adecuadas, mientras que otras simplemente están "reservadas". Son:
Todos estos son parte del lenguaje y, como tal, se pueden encontrar en cualquier texto que describa adecuadamente el idioma, como la propia Especificación de Scala (PDF).
El último, el guión bajo, merece una descripción especial, porque es muy utilizado y tiene muchos significados diferentes. Aquí hay una muestra:
Sin embargo, probablemente olvidé algún otro significado.
Métodos importados automáticamente
Por lo tanto, si no encontró el símbolo que busca en la lista anterior, debe ser un método o parte de uno. Pero, a menudo, verá algún símbolo y la documentación de la clase no tendrá ese método. Cuando esto sucede, está viendo una composición de uno o más métodos con otra cosa, o el método se ha importado al alcance o está disponible a través de una conversión implícita importada.
Estos todavía se pueden encontrar en ScalaDoc : sólo hay que saber dónde buscar para ellos. O, en su defecto, mire el índice (actualmente roto en 2.9.1, pero disponible en la noche).
Cada código Scala tiene tres importaciones automáticas:
Los dos primeros solo hacen que las clases y los objetos singleton estén disponibles. El tercero contiene todas las conversiones implícitas y métodos importados, ya que
Predef
es un objeto en sí mismo.Mirando hacia dentro
Predef
rápidamente muestra algunos símbolos:Cualquier otro símbolo estará disponible a través de una conversión implícita . Solo mire los métodos etiquetados con
implicit
esa recepción, como parámetro, un objeto de tipo que está recibiendo el método. Por ejemplo:En el caso anterior,
->
se define en la clase aArrowAssoc
través del métodoany2ArrowAssoc
que toma un objeto de tipoA
, dondeA
es un parámetro de tipo ilimitado para el mismo método.Métodos comunes
Entonces, muchos símbolos son simplemente métodos en una clase. Por ejemplo, si lo haces
Encontrará el método
++
directamente en ScalaDoc for List . Sin embargo, hay una convención que debe tener en cuenta al buscar métodos. Los métodos que terminan en dos puntos (:
) se unen a la derecha en lugar de a la izquierda. En otras palabras, mientras que la llamada al método anterior es equivalente a:Si tuviera, en cambio
1 :: List(2, 3)
, eso sería equivalente a:Por lo tanto, debe buscar el tipo que se encuentra a la derecha cuando busque métodos que terminen en dos puntos. Considere, por ejemplo:
El primer método (
+:
) se une a la derecha y se encuentra enList
. El segundo método (:+
) es solo un método normal y se une a la izquierda, nuevamente, encendidoList
.Azúcares sintácticos / composición
Entonces, aquí hay algunos azúcares sintácticos que pueden ocultar un método:
El último es interesante, porque cualquier método simbólico se puede combinar para formar un método de asignación de esa manera.
Y, por supuesto, hay varias combinaciones que pueden aparecer en el código:
fuente
val c = ex(2)
lugar deval ex(c) = 2
?val ex(c) = 2
.Una (buena, IMO) diferencia entre Scala y otros idiomas es que te permite nombrar tus métodos con casi cualquier carácter.
Lo que enumera no es "puntuación" sino métodos simples y simples, y como tal su comportamiento varía de un objeto a otro (aunque hay algunas convenciones).
Por ejemplo, consulte la documentación de Scaladoc para Lista , y verá algunos de los métodos que mencionó aquí.
Algunas cosas para tener en mente:
La mayoría de las veces la
A operator+equal B
combinación se traduce enA = A operator B
, como en los ejemplos||=
o++=
.Los métodos que terminan en
:
son asociativos correctos, esto significa queA :: B
es realmenteB.::(A)
.Encontrarás la mayoría de las respuestas navegando por la documentación de Scala. Mantener una referencia aquí duplicaría los esfuerzos, y se retrasaría rápidamente :)
fuente
Puede agruparlos primero de acuerdo con algunos criterios. En esta publicación solo explicaré el carácter de subrayado y la flecha hacia la derecha.
_._
contiene un punto Un punto en Scala siempre indica una llamada al método . A la izquierda del período que tiene el receptor, y a la derecha del mensaje (nombre del método). Ahora_
es un símbolo especial en Scala. Hay varias publicaciones al respecto, por ejemplo, esta entrada de blog, todos los casos de uso. Aquí se trata de un atajo de función anónima , es decir, un atajo para una función que toma un argumento e invoca el método_
en él. Ahora_
no es un método válido, por lo que seguramente estaba viendo_._1
o algo similar, es decir, invocar un método_._1
en el argumento de la función._1
a_22
son los métodos de tuplas que extraen un elemento particular de una tupla. Ejemplo:Ahora supongamos un caso de uso para el acceso directo de la aplicación de función. Dado un mapa que asigna enteros a cadenas:
Wooop, ya hay otra ocurrencia de una puntuación extraña. El guión y los caracteres mayores que, que se asemejan a una flecha a la derecha , es un operador que produce un
Tuple2
. Por lo tanto, no hay diferencia en el resultado de escribir(1, "Eins")
o1 -> "Eins"
, solo que este último es más fácil de leer, especialmente en una lista de tuplas como el ejemplo del mapa. No->
es magia, está, como algunos otros operadores, disponible porque tiene todas las conversiones implícitas en el objetoscala.Predef
en su alcance. La conversión que tiene lugar aquí esDonde
ArrowAssoc
tiene el->
método que crea elTuple2
. Así1 -> "Eins"
es real la llamadaPredef.any2ArrowAssoc(1).->("Eins")
. Okay. Ahora volvamos a la pregunta original con el carácter de subrayado:El guión bajo aquí acorta el siguiente código equivalente:
Tenga en cuenta que el
map
método de un Mapa pasa la tupla de clave y valor al argumento de la función. Como solo estamos interesados en los valores (las cadenas), los extraemos con el_2
método en la tupla.fuente
->
método, pero su frase "Así que no hay diferencia en el resultado de la escritura, ya sea(1, "Eins")
o1 -> "Eins"
" me ayudó a comprender la sintaxis y su uso.Como una adición a las brillantes respuestas de Daniel y 0__, tengo que decir que Scala entiende los análogos de Unicode para algunos de los símbolos, así que en lugar de
uno puede escribir
fuente
En cuanto a que
::
hay otra entrada de Stackoverflow que cubre el::
caso. En resumen, se utiliza para construirLists
' consing ' un elemento principal y una lista de cola. Es una clase que representa una lista completa y que se puede usar como extractor, pero lo más común es método en una lista. Como señala Pablo Fernández, ya que termina en dos puntos, es asociativo a la derecha , lo que significa que el receptor de la llamada al método está a la derecha y el argumento a la izquierda del operador. De esa manera se puede expresar con elegancia el Consing como anteponiendo un nuevo elemento de la cabeza a una lista existente:Esto es equivalente a
El uso como objeto extractor es el siguiente:
Esto parece un operador aquí, pero en realidad es solo otra forma (más legible) de escribir
Puedes leer más sobre extractores en esta publicación .
fuente
<=
es exactamente como lo "leerías": "menor o igual que". Entonces, es un operador matemático, en la lista de<
(¿es menor que?),>
(¿Es mayor que?),==
(¿Igual?),!=
(¿No es igual?),<=
(¿Es menor o igual?), Y>=
(es mayor que ¿o igual?).Esto no debe confundirse con
=>
cuál es una especie de doble flecha hacia la derecha , utilizada para separar la lista de argumentos del cuerpo de una función y para separar la condición de prueba en la coincidencia de patrones (uncase
bloque) del cuerpo ejecutado cuando se produce una coincidencia . Puedes ver un ejemplo de esto en mis dos respuestas anteriores. Primero, el uso de la función:que ya se abrevia a medida que se omiten los tipos. La siguiente función sería
y el uso de coincidencia de patrones:
fuente
Considero que un IDE moderno es crítico para comprender proyectos de gran escala. Como estos operadores también son métodos, en intellij idea simplemente control-click o control-b en las definiciones.
Puede hacer clic con el botón derecho del mouse en un operador de contras (: :) y terminar en el scala javadoc diciendo "Agrega un elemento al comienzo de esta lista". En los operadores definidos por el usuario, esto se vuelve aún más crítico, ya que podrían definirse en dificultades difíciles de encontrar ... su IDE sabe dónde se definió lo implícito.
fuente
Solo agregando a las otras excelentes respuestas. Scala ofrece dos operadores simbólicos a menudo criticados,
/:
(foldLeft
) y:\
(foldRight
) operadores, el primero es derecho-asociativo. Entonces las siguientes tres declaraciones son equivalentes:Como son estos tres:
fuente
Scala hereda la mayoría de los operadores aritméticos de Java . Esto incluye bitwise-or
|
(carácter de canal único), bitwise-y&
, bitwise-exclusive-or^
, así como lógico (booleano) o||
(dos caracteres de canalización) y logical-and&&
. Curiosamente, puede usar los operadores de un solo carácterboolean
, por lo que los operadores lógicos java'ish son totalmente redundantes:Como se señaló en otra publicación, las llamadas que terminan en un signo de igual
=
se resuelven (si no existe un método con ese nombre) mediante una reasignación:Este 'doble control' hace posible intercambiar fácilmente un mutable por una colección inmutable:
fuente
true | { println( "Icke" ); true }
⇒ imprime!true || { println( "Icke" ); true }
⇒ no imprime!