Je divise les opérateurs, à des fins d'enseignement, en quatre catégories :
- Mots-clés / symboles réservés
- Méthodes importées automatiquement
- Méthodes courantes
- 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, <=
on Int
signifie "inférieur ou égal à" . Le premier ->
, je vais donner comme exemple ci-dessous. ::
est probablement la méthode définie sur List
(bien qu'elle puisse être l'objet du même nom), et :+=
est probablement la méthode définie sur différentes Buffer
classes.
Alors, voyons-les.
Mots-clés / symboles réservés
Il y a quelques symboles dans Scala qui sont spéciaux. Deux d'entre eux sont considérés comme des mots clés appropriés, tandis que d'autres sont simplement "réservés". Elles sont:
// 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
Ils font tous partie de la langue et, en tant que tels, peuvent être trouvés dans n'importe quel texte décrivant correctement la langue, comme la spécification Scala (PDF) elle-même.
Le dernier, le trait de soulignement, mérite une description spéciale, car il est si largement utilisé et a tellement de significations différentes. 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 celle-ci. Mais, souvent, vous verrez un symbole et la documentation de la classe n'aura pas cette méthode. Lorsque cela se produit, soit vous regardez une composition d'une ou plusieurs méthodes avec quelque chose d'autre, soit la méthode a été importée dans la portée, ou est disponible via une conversion implicite importée.
Ceux-ci peuvent toujours être trouvés sur ScalaDoc : il suffit de savoir où les chercher. Ou, à défaut, regardez l' index (actuellement cassé le 2.9.1, mais disponible le soir).
Chaque code Scala a 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. Le troisième contient toutes les conversions implicites et les méthodes importées, puisqu'il Predef
s'agit d'un objet lui-même.
Regarder à l'intérieur Predef
montre rapidement quelques symboles:
class <:<
class =:=
object <%<
object =:=
Tout autre symbole sera rendu disponible par une conversion implicite . Regardez simplement les méthodes marquées avec implicit
qui reçoivent, en tant que paramètre, un objet de 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
via la méthode any2ArrowAssoc
qui prend un objet de type A
, oùA
est un paramètre de type illimité vers la même méthode.
Méthodes courantes
Ainsi, de nombreux symboles sont simplement des méthodes sur une classe. Par exemple, si vous le faites
List(1, 2) ++ List(3, 4)
Vous trouverez la méthode ++
directement sur ScalaDoc for List . Cependant, il existe une convention que vous devez connaître lors de la recherche de méthodes. Les méthodes se terminant par deux points ( :
) se lient à droite au lieu de gauche. En d'autres termes, alors que l'appel de méthode ci-dessus équivaut à:
List(1, 2).++(List(3, 4))
Si je l'avais, cela 1 :: List(2, 3)
équivaudrait à:
List(2, 3).::(1)
Vous devez donc regarder le type trouvé à droite lorsque vous recherchez des méthodes se terminant par deux points. Considérez, par exemple:
1 +: List(2, 3) :+ 4
La première méthode ( +:
) se lie à droite et se trouve sur List
. La deuxième méthode ( :+
) est juste une méthode normale, et se lie à gauche - encore une fois, surList
.
Sucres syntaxiques / composition
Voici donc quelques sucres syntaxiques qui peuvent masquer 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
La dernière est intéressante, car toute méthode symbolique peut être combinée pour former une méthode de type affectation de cette façon.
Et, bien sûr, différentes combinaisons 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.