Ich unterteile die Betreiber für die Zwecke des Unterrichts in vier Kategorien :
- Schlüsselwörter/reservierte Symbole
- Automatisch importierte Methoden
- Gemeinsame 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, <=
auf Int
bedeutet "weniger als oder gleich" . Die erste, ->
Ich gebe im Folgenden ein Beispiel. ::
ist wahrscheinlich die Methode, die auf List
(obwohl es podría das gleichnamige Objekt sein), und :+=
ist wahrscheinlich die Methode, die in verschiedenen Buffer
Klassen.
Schauen wir sie uns also an.
Schlüsselwörter/reservierte Symbole
Es gibt einige Symbole in Scala, die besonders sind. Zwei davon gelten als richtige Schlüsselwörter, während andere einfach "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 kann als solches in jedem Text gefunden werden, der die Sprache richtig beschreibt, wie z. B. Scala-Spezifikation (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 aber eine andere Bedeutung vergessen.
Automatisch importierte Methoden
Wenn Sie also das gesuchte Symbol in der obigen Liste nicht gefunden haben, muss es sich um eine Methode oder einen Teil einer Methode handeln. Oftmals sehen Sie jedoch ein Symbol und die Dokumentation der Klasse enthält diese Methode nicht. Wenn dies der Fall ist, handelt es sich entweder um eine Komposition einer oder mehrerer Methoden mit etwas anderem, oder die Methode wurde in den Geltungsbereich importiert oder ist durch eine importierte implizite Konvertierung verfügbar.
Diese kann noch gefunden werden auf ScalaDoc Man muss nur wissen, wo man sie suchen muss. Oder, wenn das nicht möglich ist, schauen Sie sich die Index (zur Zeit unter 2.9.1 defekt, aber unter Nightly verfügbar).
Jeder Scala-Code hat 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 machen nur Klassen und Singleton-Objekte verfügbar. Die dritte enthält alle impliziten Konvertierungen und importierten Methoden, da Predef
ist selbst ein Objekt.
Blick ins Innere Predef
schnell einige Symbole zeigen:
class <:<
class =:=
object <%<
object =:=
Jedes andere Symbol wird über ein implizite Umrechnung . Sehen Sie sich nur die Methoden an, die mit implicit
die als Parameter ein Objekt des Typs erhalten, der die Methode empfängt. Zum Beispiel:
"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter
In dem oben genannten Fall, ->
ist definiert in der Klasse ArrowAssoc
durch die Methode any2ArrowAssoc
die ein Objekt des Typs A
donde A
ist ein unbegrenzter Typparameter für dieselbe Methode.
Gemeinsame Methoden
Viele Symbole sind also einfach Methoden einer Klasse. Zum Beispiel, wenn Sie
List(1, 2) ++ List(3, 4)
Sie finden die Methode ++
direkt in der ScalaDoc für Liste . Es gibt jedoch eine Konvention, die Sie bei der Suche nach Methoden beachten müssen. Methoden, die mit einem Doppelpunkt ( :
) binden auf der rechten Seite statt der linken. Mit anderen Worten, während der obige Methodenaufruf äquivalent zu ist:
List(1, 2).++(List(3, 4))
Hätte ich stattdessen 1 :: List(2, 3)
wäre das gleichbedeutend mit:
List(2, 3).::(1)
Sie müssen sich also den gefundenen Typ ansehen auf der rechten Seite bei der Suche nach Methoden, die mit Doppelpunkt enden. Nehmen wir zum Beispiel:
1 +: List(2, 3) :+ 4
Die erste Methode ( +:
) bindet nach rechts und findet sich auf List
. Die zweite Methode ( :+
) ist nur eine normale Methode und bindet an die linke Seite - wiederum an List
.
Syntaktische Zucker/Zusammensetzung
Hier also ein paar syntaktische Zucker, hinter denen sich eine Methode verbergen kann:
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
Der letzte Punkt ist interessant, denn jede symbolische Methode kann auf diese Weise zu einer zuweisungsähnlichen Methode kombiniert werden.
Und natürlich gibt es verschiedene Kombinationen, die im Code vorkommen 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.