433 votes

Que signifient tous les opérateurs symboliques de Scala ?

La syntaxe Scala comporte de nombreux symboles. Étant donné que ce type de noms est difficile à trouver à l'aide des moteurs de recherche, une liste exhaustive de ceux-ci serait utile.

Quels sont tous les symboles en Scala, et à quoi sert chacun d'entre eux ?

En particulier, j'aimerais en savoir plus sur -> , ||= , ++= , <= , _._ , :: y :+= .

4 votes

Et l'index de Staircase 1ère édition, à >> artima.com/pins1ed/livre-index.html#indexanchor

2 votes

Related : caractères d'opérateur vs caractères alphanumériques : stackoverflow.com/questions/7656937/

1 votes

Également, s'il y a des "opérateurs" (qui sont principalement des méthodes, avec quelques noms de classes utilisés de manière infixe) que vous ne trouvez pas dans scalex ou le livre de l'escalier, par exemple " !!", les sources probables sont les scaladocs pour akka, scalaz et sbt

562voto

Daniel C. Sobral Points 159554

Je divise les opérateurs, pour les besoins de l'enseignement, en quatre catégories :

  • Mots clés/symboles réservés
  • Méthodes importées automatiquement
  • Méthodes communes
  • Sucres syntaxiques/composition

Il est donc heureux que la plupart des catégories soient représentées dans la question :

->    // Automatically imported method
||=   // Syntactic sugar
++=   // Syntactic sugar/composition or common method
<=    // Common method
_._   // Typo, though it's probably based on Keyword/composition
::    // Common method
:+=   // Common method

La signification exacte de la plupart de ces méthodes dépend de la classe qui les définit. Par exemple, <= en Int signifie "inférieur ou égal à" . Le premier, -> Je vais vous donner un exemple ci-dessous. :: est probablement la méthode définie sur List (bien qu'il pourrait soit l'objet du même nom), et :+= est probablement la méthode définie sur divers Buffer classes.

Alors, voyons-les.

Mots clés/symboles réservés

Certains symboles en Scala sont spéciaux. Deux d'entre eux sont considérés comme des mots-clés appropriés, tandis que les autres sont simplement "réservés". Ce sont les suivants :

// Keywords
<-  // Used on for-comprehensions, to separate pattern from generator
=>  // Used for function types, function literals and import renaming

// Reserved
( )        // Delimit expressions and parameters
[ ]        // Delimit type parameters
{ }        // Delimit blocks
.          // Method call and path separator
// /* */   // Comments
#          // Used in type notations
:          // Type ascription or context bounds
<: >: <%   // Upper, lower and view bounds
<? <!      // Start token for various XML elements
" """      // Strings
'          // Indicate symbols and characters
@          // Annotations and variable binding on pattern matching
`          // Denote constant or enable arbitrary identifiers
,          // Parameter separator
;          // Statement separator
_*         // vararg expansion
_          // Many different meanings

Ce sont tous partie de la langue et, en tant que telle, elle peut être trouvée dans tout texte décrivant correctement la langue, tel que Spécification Scala (PDF) lui-même.

Le dernier, le trait de soulignement, mérite une description spéciale, car il est très largement utilisé et a de nombreuses significations différentes. En voici un exemple :

import scala._    // Wild card -- all of Scala is imported
import scala.{ Predef => _, _ } // Exception, everything except Predef
def f[M[_]]       // Higher kinded type parameter
def f(m: M[_])    // Existential type
_ + _             // Anonymous function placeholder parameter
m _               // Eta expansion of method into method value
m(_)              // Partial function application
_ => 5            // Discarded parameter
case _ =>         // Wild card pattern -- matches anything
f(xs: _*)         // Sequence xs is passed as multiple parameters to f(ys: T*)
case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequence

J'ai probablement oublié une autre signification, cependant.

Méthodes importées automatiquement

Donc, si vous n'avez pas trouvé le symbole que vous recherchez dans la liste ci-dessus, il doit s'agir d'une méthode, ou d'une partie de méthode. Mais, souvent, vous verrez un symbole et la documentation de la classe ne contiendra pas cette méthode. Dans ce cas, il s'agit soit d'une composition d'une ou plusieurs méthodes avec quelque chose d'autre, soit d'une méthode importée dans le champ d'application, soit d'une méthode disponible via une conversion implicite importée.

Ces peuvent encore être trouvés en ScalaDoc Il faut juste savoir où les chercher. Ou, à défaut, regardez le indice (actuellement cassé sur 2.9.1, mais disponible sur nightly).

Chaque code Scala comporte trois importations automatiques :

// Not necessarily in this order
import _root_.java.lang._      // _root_ denotes an absolute path
import _root_.scala._
import _root_.scala.Predef._

Les deux premiers ne rendent disponibles que les classes et les objets singleton. La troisième contient toutes les conversions implicites et les méthodes importées, puisque Predef est un objet lui-même.

Regarder à l'intérieur Predef montrer rapidement quelques symboles :

class <:<
class =:=
object <%<
object =:=

Tout autre symbole sera mis à disposition par le biais d'un conversion implicite . Il suffit de regarder les méthodes étiquetées avec implicit qui reçoivent, comme paramètre, un objet du type qui reçoit la méthode. Par exemple :

"a" -> 1  // Look for an implicit from String, AnyRef, Any or type parameter

Dans le cas ci-dessus, -> est défini dans la classe ArrowAssoc par la méthode any2ArrowAssoc qui prend un objet de type A , donde A est un paramètre de type non borné de la même méthode.

Méthodes communes

Ainsi, de nombreux symboles sont simplement des méthodes sur une classe. Par exemple, si vous faites

List(1, 2) ++ List(3, 4)

Vous trouverez la méthode ++ directement sur la ScalaDoc pour Liste . Cependant, il y a une convention dont vous devez être conscient lorsque vous recherchez des méthodes. Les méthodes se terminant par deux points ( : ) lier à droite au lieu de la gauche. En d'autres termes, alors que l'appel de méthode ci-dessus est équivalent à :

List(1, 2).++(List(3, 4))

Si j'avais, à la place 1 :: List(2, 3) ce qui équivaudrait à :

List(2, 3).::(1)

Donc vous devez regarder le type trouvé à droite lors de la recherche de méthodes se terminant par deux points. Considérez, par exemple :

1 +: List(2, 3) :+ 4

La première méthode ( +: ) se lie à la droite, et se trouve sur List . La deuxième méthode ( :+ ) est juste une méthode normale, et se lie à la gauche -- encore une fois, sur List .

Sucres syntaxiques/composition

Voici donc quelques sucres syntaxiques qui peuvent cacher une méthode :

class Example(arr: Array[Int] = Array.fill(5)(0)) {
  def apply(n: Int) = arr(n)
  def update(n: Int, v: Int) = arr(n) = v
  def a = arr(0); def a_=(v: Int) = arr(0) = v
  def b = arr(1); def b_=(v: Int) = arr(1) = v
  def c = arr(2); def c_=(v: Int) = arr(2) = v
  def d = arr(3); def d_=(v: Int) = arr(3) = v
  def e = arr(4); def e_=(v: Int) = arr(4) = v
  def +(v: Int) = new Example(arr map (_ + v))
  def unapply(n: Int) = if (arr.indices contains n) Some(arr(n)) else None
}

val Ex = new Example // or var for the last example
println(Ex(0))  // calls apply(0)
Ex(0) = 2       // calls update(0, 2)
Ex.b = 3        // calls b_=(3)
// This requires Ex to be a "val"
val Ex(c) = 2   // calls unapply(2) and assigns result to c
// This requires Ex to be a "var"
Ex += 1         // substituted for Ex = Ex + 1

Le dernier point est intéressant, car tout La méthode symbolique peut être combinée de cette façon pour former une méthode semblable à celle de l'affectation.

Et, bien sûr, il y a diverses combinaisons qui peuvent apparaître dans le code :

(_+_) // An expression, or parameter, that is an anonymous function with
      // two parameters, used exactly where the underscores appear, and
      // which calls the "+" method on the first parameter passing the
      // second parameter as argument.

1 votes

Voulez-vous dire val c = ex(2) au lieu de val ex(c) = 2 ?

3 votes

Non, je voulais dire val ex(c) = 2 .

0 votes

Oh, ça utilise la syntaxe du filtrage. Merci.

26voto

Pablo Fernandez Points 32003

Une (bonne, IMO) différence entre Scala et les autres langages est qu'il vous permet de nommer vos méthodes avec presque n'importe quel caractère.

Ce que vous énumérez n'est pas de la "ponctuation" mais de simples méthodes, et en tant que telles, leur comportement varie d'un objet à l'autre (bien qu'il existe certaines conventions).

Par exemple, vérifiez le Documentation Scaladoc pour List et vous verrez certaines des méthodes que vous avez mentionnées ici.

Quelques éléments à garder à l'esprit :

  • La plupart du temps, le A operator+equal B La combinaison se traduit par A = A operator B comme dans le ||= o ++= exemples.

  • Les méthodes qui se terminent par : sont associatives à droite, cela signifie que A :: B est en fait B.::(A) .

Vous trouverez la plupart des réponses en parcourant la documentation de Scala. Conserver une référence ici reviendrait à dupliquer les efforts, et cela prendrait vite du retard :)

21voto

0__ Points 23597

Vous pouvez d'abord les regrouper en fonction de certains critères. Dans cet article, je vais simplement expliquer le caractère de soulignement et la flèche droite.

_._ contient un point. Un point en Scala indique toujours un appel de méthode . Ainsi, à gauche de la période, vous avez le récepteur, et à droite de celui-ci, le message (nom de la méthode). Maintenant, _ est un symbole spécial en Scala. Il existe plusieurs articles à ce sujet, par exemple cet article de blog tous les cas d'utilisation. Il s'agit ici d'un raccourci de la fonction anonyme c'est-à-dire un raccourci pour une fonction qui prend un argument et invoque la méthode _ sur elle. Maintenant _ n'est pas une méthode valide, donc très certainement vous avez vu _._1 ou quelque chose de similaire, c'est-à-dire invoquer la méthode _._1 sur l'argument de la fonction. _1 a _22 sont les méthodes de tuples qui extraient un élément particulier d'un tuple. Exemple :

val tup = ("Hallo", 33)
tup._1 // extracts "Hallo"
tup._2 // extracts 33

Supposons maintenant un cas d'utilisation du raccourci d'application de la fonction. Étant donné une carte qui fait correspondre des entiers à des chaînes de caractères :

val coll = Map(1 -> "Eins", 2 -> "Zwei", 3 -> "Drei")

Wooop, il y a déjà une autre occurrence d'une ponctuation étrange. Le trait d'union et le caractère plus grand que, qui ressemble à un flèche droite est un opérateur qui produit un Tuple2 . Donc il n'y a pas de différence dans le résultat de l'écriture soit (1, "Eins") o 1 -> "Eins" mais la seconde est plus facile à lire, surtout dans une liste de tuples comme dans l'exemple de la carte. Le site -> n'est pas magique, elle est, comme quelques autres opérateurs, disponible parce que vous avez tous les implicite conversions en objet scala.Predef dans son champ d'application. La conversion qui a lieu ici est

implicit def any2ArrowAssoc [A] (x: A): ArrowAssoc[A] 

Dónde ArrowAssoc a le -> qui crée la méthode Tuple2 . Así, 1 -> "Eins" est effectif l'appel Predef.any2ArrowAssoc(1).->("Eins") . Ok. Revenons maintenant à la question initiale avec le caractère de soulignement :

// lets create a sequence from the map by returning the
// values in reverse.
coll.map(_._2.reverse) // yields List(sniE, iewZ, ierD)

Le trait de soulignement raccourcit ici le code équivalent suivant :

coll.map(tup => tup._2.reverse)

Notez que le map d'une Map transmet le tuple de clé et de valeur à l'argument de la fonction. Puisque nous ne sommes intéressés que par les valeurs (les chaînes de caractères), nous les extrayons avec la fonction _2 sur le tuple.

0 votes

+1 J'avais du mal à comprendre le -> mais votre phrase "Il n'y a donc pas de différence dans le résultat de l'écriture de l'une ou l'autre (1, "Eins") o 1 -> "Eins" "m'a aidé à comprendre la syntaxe et son utilisation.

0 votes

Fyi le lien de votre blog est mort

16voto

om-nom-nom Points 33691

Pour compléter les brillantes réponses de Daniel et de 0__, je dois dire que Scala comprend les éléments suivants Unicode analogues pour certains des symboles, donc au lieu de

for (n <- 1 to 10) n % 2 match {
  case 0 => println("even")
  case 1 => println("odd")
}

on peut écrire

for (n ← 1 to 10) n % 2 match {
  case 0 ⇒ println("even")
  case 1 ⇒ println("odd")
}

9voto

0__ Points 23597

<= c'est comme si vous le "lisiez" : "moins que ou égale". Il s'agit donc d'un opérateur mathématique, dans la liste de < (est moins que ?), > (est plus grand que ?), == (égaux ?), != (n'est pas égal ?), <= (est inférieur ou égal ?), et >= (est supérieur ou égal ?).

Cela ne doit pas être confus con => qui est une sorte de double flèche droite utilisé pour séparer la liste d'arguments du corps d'une fonction et pour séparer la condition de test dans la correspondance de motifs (un case ) du corps exécuté lorsqu'une correspondance se produit. Vous pouvez voir un exemple de ceci dans mes deux réponses précédentes. D'abord, l'utilisation de la fonction :

coll.map(tup => tup._2.reverse)

qui est déjà abrégé puisque les types sont omis. La fonction suivante serait

// function arguments         function body
(tup: Tuple2[Int, String]) => tup._2.reverse

et l'utilisation du filtrage :

def extract2(l: List[Int]) = l match {
   // if l matches Nil    return "empty"
   case Nil            => "empty"
   // etc.
   case ::(head, Nil)  => "exactly one element (" + head + ")"
   // etc.
   case ::(head, tail) => "more than one element"
}

4 votes

Éviter cette confusion est la raison pour laquelle j'ai décidé de commencer à utiliser les caractères unicode pour la double flèche droite ( \U21D2 ), la flèche unique droite "cartes" ( \U2192 ), et la flèche unique gauche "in" ( \U2190 ). Scala supporte cela mais j'étais un peu sceptique jusqu'à ce que je l'essaie pendant un moment. Il suffit de chercher comment lier ces points de code à une combinaison de touches pratique sur votre système. C'était vraiment facile sous OS X.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X