Comprendre l'opérateur appel et de contre méthode infix (: :) à Scala
-
02-10-2019 - |
Question
Je suis tout à fait nouveau pour le langage de programmation Scala, et a essayé quelque chose stucked dans mon esprit pendant que je suivais les notes de cours à ici .
Je pense que je ne pouvais pas vraiment comprendre comment opérateur contre les travaux, voici quelques choses que j'essayées:
J'ai créé un générateur de nombres pseudo-aléatoires, puis essayé de créer une liste d'une valeur aléatoire:
scala> val gen = new java.util.Random
gen: java.util.Random = java.util.Random@1b27332
scala> gen nextInt 3 :: Nil
<console>:7: error: type mismatch;
found : List[Int]
required: Int
gen nextInt 3 :: Nil
^
Mais il a essayé de passer la liste (3) à la méthode nextnt. Quand je paratheses, il n'y avait pas de problème
scala> (gen nextInt 3) :: Nil
res69: List[Int] = List(1)
J'étais curieux de connaître l'ordre d'exécution, donc je créé une fonction pour vérifier
scala> def pr(i:Int):Int = { println(i); i }
pr: (i: Int)Int
scala> pr(1) :: pr(2) :: pr(3) :: Nil
1
2
3
res71: List[Int] = List(1, 2, 3)
Comme on le voit dans les sorties, l'ordre d'exécution est le même que l'ordre d'apparition. Ensuite, je pensais que ce serait peut-être au sujet de la fonction « nextInt », puis j'ai essayé suivante:
scala> 1 + 2 :: Nil
res72: List[Int] = List(3)
Il a d'abord exécuté plus, et après que le contre est exécuté. Voici donc la question: Quelle est la différence entre gen nextInt 3 :: Nil
et 1 + 2 :: Nil
La solution
Il y a deux choses préoccupantes ici: priorité et fixité . Comme sepp2k mentionné, cette question sur Stack Overflow explique la priorité, la pensée des règles, cité, ne sont pas assez complètes, et il y avait de très petits changements de Scala 2.7 à 2.8 Scala. Les différences concernent la plupart des opérateurs se terminant en =
, cependant.
pour fixité , presque tout à Scala est lu de gauche à droite, ce qui est ce que les programmeurs sont habitués. En Scala, cependant, les opérateurs se terminant en :
sont lues de droite à gauche.
Prenez donc cet exemple:
1 + 2 :: Nil
Tout d'abord, la priorité. Ce qui a le plus prioritaire, +
ou :
? Selon le tableau, +
a préséance sur :
, de sorte que l'addition est fait en premier. Par conséquent, l'expression est égale à ceci:
((1).+(2)) :: Nil
Maintenant, il n'y a pas de conflit de priorité, mais depuis les extrémités de ::
dans :
, il a une fixité diferent. Il est lu de droite à gauche, donc:
Nil.::((1).+(2))
D'autre part, en ceci:
gen nextInt 3 :: Nil
Le ::
opérateur a priorité sur nextInt
, parce que :
a préséance sur toutes les lettres. Par conséquent, et en se rappelant sa fixité, il devient:
gen nextInt Nil.::(3)
Ce qui devient alors
gen.nextInt(Nil.::(3))
A quel point l'erreur est évidente.
PS: J'écris (1).+(2)
au lieu de 1.+(2)
parce que, au moment où nous écrivons ces lignes, 1.
est interprété comme un nombre double, ce qui 1.+(2)
une expression infixe ajoutant la double 1,0 à 2. Cette syntaxe est obsolète depuis Scala 2.10 .0, et ne sera probablement pas présent sur Scala 2,11.
Autres conseils
Il est sur la priorité de ne pas l'ordre d'exécution. +
a une priorité supérieure ::
, donc Parsis de a + b :: c
comme (a + b) :: c
. Cependant les appels de méthode infix avec des noms réguliers ont une priorité plus faible, de sorte Parsis de a foo b c
comme a foo (b c)
.
Voir cette question pour une liste des opérateurs classés par leur ordre de priorité dans scala.