studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones list scala operator-keyword

list - programacion - El operador ''::'' de Scala, ¿cómo funciona?



manual de programacion android pdf (4)

En Scala, puedo hacer una case class Foo(x:Int) , case class Foo(x:Int) , y luego ponerlo en una lista como esta:

List(Foo(42))

Ahora, nada extraño aquí. Lo siguiente es extraño para mí. El operador :: es una función en una lista, ¿verdad? Con cualquier función con un argumento en Scala, puedo llamarlo con notación de infijo. Un ejemplo es 1 + 2 es una función (+) en el objeto Int . La clase Foo que acabo de definir no tiene el operador :: así que, ¿cómo es posible lo siguiente?

Foo(40) :: List(Foo(2))

En Scala 2.8 RC1, obtengo el siguiente resultado del indicador interactivo:

scala> case class Foo(x:Int) defined class Foo scala> Foo(40) :: List(Foo(2)) res2: List[Foo] = List(Foo(40), Foo(2))

Puedo seguir y usarlo, pero ¿cuál es la explicación?


La clase Foo que acabo de definir no tiene el operador :: así que, ¿cómo es posible lo siguiente:

Foo(40) :: List(Foo(2))

Si el nombre del método termina con dos puntos (:), el método se invoca en el operando derecho , que es el caso aquí. Si el nombre del método no termina con dos puntos, el método se invoca en el operando de la izquierda. Por ejemplo, a + b , + se invoca en a .

Entonces, en su ejemplo, :: es un método en su operando derecho, que es una List .


De la especificación:

6.12.3 InfixOperations Un operador de infijo puede ser un identificador arbitrario. Los operadores de infijo tienen prioridad y asociatividad definida de la siguiente manera.

...

La asociatividad de un operador está determinada por el último carácter del operador. Los operadores que terminan en dos puntos '':'' son asociativos por derecho. Todos los demás operadores son asociativos por la izquierda.

Siempre puede ver cómo se aplican estas reglas en Scala imprimiendo el programa después de que haya pasado por la fase de "tipificación" del compilador:

scala -Xprint:typer -e "1 :: Nil" val r: List[Int] = { <synthetic> val x$1: Int = 1; immutable.this.Nil.::[Int](x$1) };


Termina con una : Y ese es el signo de que esta función está definida en la clase a la derecha (en la clase List aquí).

Entonces, es List(Foo(2)).::(Foo(40)) , no Foo(40).::(List(Foo(2))) en su ejemplo.


Un aspecto que falta en las respuestas es que para admitir :: en expresiones de coincidencia de patrones:

List(1,2) match { case x :: xs => println(x + " " + xs) case _ => println("") }

Una clase :: se define :

final case class ::[B](private var hd: B, private[scala] var tl: List[B])

así case ::(x,xs) produciría el mismo resultado. La expresión case x :: xs funciona porque el extractor predeterminado :: está definido para la clase de caso y se puede usar infijo.