Opérateur '::' de Scala, comment ça marche?

en Scala, je peux faire une classe cas, case class Foo(x:Int) , et puis le mettre dans une liste comme ça:

List(Foo(42))

Maintenant, rien d'étrange ici. Ce qui suit est étrange pour moi. L'opérateur :: est une fonction sur une liste, non? Avec n'importe quelle fonction avec un argument dans Scala, je peux l'appeler avec la notation infix. Un exemple est 1 + 2 est une fonction (+) sur l'objet Int . La classe Foo que je viens de définir n'a pas le :: opérateur, quel est donc le suivant?

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

dans Scala 2.8 RC1, j'obtiens le résultat suivant de l'invite interactive:

scala> case class Foo(x:Int)
defined class Foo

scala> Foo(40) :: List(Foo(2))
res2: List[Foo] = List(Foo(40), Foo(2))

je peux continuer et l'utiliser, mais quelle est l'explication?

47
demandé sur nbro 2010-05-13 17:52:52

4 réponses

De la Spec:

6.12.3 InfixOperations un opérateur infix peut être un arbitraire identificateur. Les opérateurs infixes ont priorité et associativité des opérateurs définis comme suit.

...

l'associativité d'un opérateur est déterminé par l'opérateur du dernier caractère. Opérateurs se terminant par un côlon ‘:’ sont associatifs droit. Tous les autres les opérateurs sont associatifs gauche.

vous pouvez toujours voir comment ces règles sont appliquées dans Scala en imprimant le programme après qu'il a été à travers la phase de "typer" du compilateur:

scala -Xprint:typer -e "1 :: Nil"

val r: List[Int] = {
  <synthetic> val x: Int = 1;
  immutable.this.Nil.::[Int](x)
};
46
répondu retronym 2010-05-13 14:10:59

il se termine par un : . Et c'est le signe, que cette fonction est définie dans la classe à droite (dans la classe List ici).

Donc, c'est List(Foo(2)).::(Foo(40)) , pas Foo(40).::(List(Foo(2))) dans votre exemple.

20
répondu folone 2010-05-13 14:21:13

un aspect manquant dans les réponses données est que pour soutenir :: dans les expressions de correspondance de modèle:

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

d'Une classe :: est défini :

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

ainsi case ::(x,xs) produirait le même résultat. L'expression case x :: xs fonctionne parce que l'extracteur par défaut :: est défini pour la classe de cas et il peut être utilisé infix.

16
répondu Thomas Jung 2010-05-18 11:54:47

la classe Foo que je viens de définir n'est pas avoir l'opérateur :: , alors comment est le suivant possible:

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

si le nom de la méthode se termine par un deux-points ( : ) la méthode est invoquée sur le opérande de droite , ce qui est le cas ici. Si le nom de la méthode ne se termine pas par deux points, la méthode est invoquée sur l'opérande de gauche. Exemple, a + b , + est invoqué sur a .

Alors, dans votre exemple, :: est une méthode sur son opérande de droite, qui est un List .

15
répondu Surya Suravarapu 2017-05-15 13:15:10