Ich teile die Operatoren zum Zweck des Unterrichts in vier Kategorien ein :
- Schlüsselwörter / reservierte Symbole
- Automatisch importierte Methoden
- Gängige Methoden
- Syntaktische Zucker / Zusammensetzung
Es ist also ein Glück, dass die meisten Kategorien in der Frage vertreten sind:
-> // 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
Die genaue Bedeutung der meisten dieser Methoden hängt von der Klasse ab, die sie definiert. Zum Beispiel bedeutet <=
on "kleiner oder gleich" . Das erste werde ich als Beispiel unten geben. ist wahrscheinlich die Methode, für die definiert wurde (obwohl es sich um das gleichnamige Objekt handeln könnte ), und wahrscheinlich die Methode, die für verschiedene Klassen definiert wurde .Int
->
::
List
:+=
Buffer
Also, lasst uns sie sehen.
Schlüsselwörter / reservierte Symbole
Es gibt einige Symbole in Scala, die besonders sind. Zwei von ihnen werden als richtige Schlüsselwörter angesehen, während andere nur "reserviert" sind. Sie sind:
// 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
Diese sind alle Teil der Sprache und können als solche in jedem Text gefunden werden, der die Sprache richtig beschreibt, wie z. B. Scala Specification (PDF) selbst.
Der letzte, der Unterstrich, verdient eine besondere Beschreibung, weil er so weit verbreitet ist und so viele verschiedene Bedeutungen hat. Hier ist ein Beispiel:
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
Wahrscheinlich habe ich jedoch eine andere Bedeutung vergessen.
Automatisch importierte Methoden
Wenn Sie das gesuchte Symbol in der obigen Liste nicht gefunden haben, muss es eine Methode oder ein Teil davon sein. Oft wird jedoch ein Symbol angezeigt, und die Dokumentation für die Klasse enthält diese Methode nicht. In diesem Fall betrachten Sie entweder eine Zusammensetzung einer oder mehrerer Methoden mit etwas anderem, oder die Methode wurde in den Gültigkeitsbereich importiert oder ist über eine importierte implizite Konvertierung verfügbar.
Diese sind immer noch auf ScalaDoc zu finden : Sie müssen nur wissen, wo Sie sie suchen müssen. Andernfalls sehen Sie sich den Index an (derzeit auf 2.9.1 defekt, aber abends verfügbar).
Jeder Scala-Code verfügt über drei automatische Importe:
// Not necessarily in this order
import _root_.java.lang._ // _root_ denotes an absolute path
import _root_.scala._
import _root_.scala.Predef._
Die ersten beiden stellen nur Klassen und Singleton-Objekte zur Verfügung. Die dritte enthält alle impliziten Konvertierungen und importierten Methoden, da Predef
es sich um ein Objekt selbst handelt.
Wenn Sie Predef
schnell hineinschauen, sehen Sie einige Symbole:
class <:<
class =:=
object <%<
object =:=
Jedes andere Symbol wird durch eine implizite Konvertierung verfügbar gemacht . Schauen Sie sich einfach die mit implicit
diesem Tag gekennzeichneten Methoden an , die als Parameter ein Objekt vom Typ erhalten, das die Methode empfängt. Zum Beispiel:
"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter
Im obigen Fall ->
wird in der Klasse ArrowAssoc
durch die Methode definiert any2ArrowAssoc
, die ein Objekt vom Typ übernimmt A
, wobei A
ein unbegrenzter Typparameter für dieselbe Methode gilt.
Gängige Methoden
Viele Symbole sind also einfach Methoden für eine Klasse. Zum Beispiel, wenn Sie dies tun
List(1, 2) ++ List(3, 4)
Sie finden die Methode ++
direkt in der ScalaDoc for List . Es gibt jedoch eine Konvention, die Sie bei der Suche nach Methoden beachten müssen. Methoden, die mit Doppelpunkt ( :
) enden , werden rechts statt links gebunden. Mit anderen Worten, während der obige Methodenaufruf äquivalent ist zu:
List(1, 2).++(List(3, 4))
Wenn ich stattdessen 1 :: List(2, 3)
hätte, wäre das gleichbedeutend mit:
List(2, 3).::(1)
Sie müssen sich also den Typ auf der rechten Seite ansehen, wenn Sie nach Methoden suchen, die mit einem Doppelpunkt enden. Betrachten Sie zum Beispiel:
1 +: List(2, 3) :+ 4
Die erste Methode ( +:
) bindet nach rechts und befindet sich auf List
. Die zweite Methode ( :+
) ist nur eine normale Methode und bindet nach links - wieder auf List
.
Syntaktische Zucker / Zusammensetzung
Hier sind einige syntaktische Zucker, die eine Methode verbergen können:
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
Die letzte ist interessant, weil jede symbolische Methode auf diese Weise zu einer zuweisungsähnlichen Methode kombiniert werden kann.
Und natürlich gibt es verschiedene Kombinationen, die im Code erscheinen können:
(_+_) // 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.