Do celów nauczania dzielę operatorów na cztery kategorie :
- Słowa kluczowe / symbole zastrzeżone
- Metody importowane automatycznie
- Wspólne metody
- Cukry syntaktyczne / skład
Na szczęście zatem większość kategorii jest reprezentowana w pytaniu:
-> // 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
Dokładne znaczenie większości tych metod zależy od klasy, która je definiuje. Na przykład <=
on Int
oznacza „mniejszy lub równy” . Pierwszy, ->
podam jako przykład poniżej. ::
jest prawdopodobnie metodą zdefiniowaną na List
(choć może to być obiekt o tej samej nazwie) i :+=
prawdopodobnie jest metodą zdefiniowaną dla różnych Buffer
klas.
Zobaczmy ich.
Słowa kluczowe / symbole zastrzeżone
W Scali jest kilka symboli, które są wyjątkowe. Dwa z nich są uważane za właściwe słowa kluczowe, a inne są po prostu „zastrzeżone”. Oni są:
// 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
Wszystkie są częścią języka i jako takie można je znaleźć w dowolnym tekście, który prawidłowo opisuje ten język, takim jak sama specyfikacja Scala (PDF).
Ostatni, podkreślenie, zasługuje na specjalny opis, ponieważ jest tak szeroko stosowany i ma tak wiele różnych znaczeń. Oto próbka:
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
Prawdopodobnie zapomniałem jednak o innym znaczeniu.
Metody importowane automatycznie
Tak więc, jeśli nie znalazłeś szukanego symbolu na powyższej liście, to musi to być metoda lub jej część. Ale często zobaczysz jakiś symbol, a dokumentacja dla klasy nie będzie miała tej metody. Kiedy tak się dzieje, albo patrzysz na kompozycję jednej lub więcej metod z czymś innym, albo metoda została zaimportowana do zakresu lub jest dostępna poprzez zaimportowaną niejawną konwersję.
Są nadal można znaleźć na ScalaDoc : po prostu trzeba wiedzieć gdzie ich szukać. Lub, jeśli to nie wystarczy, spójrz na indeks (obecnie uszkodzony w wersji 2.9.1, ale dostępny w nocy).
Każdy kod Scala ma trzy automatyczne importy:
// Not necessarily in this order
import _root_.java.lang._ // _root_ denotes an absolute path
import _root_.scala._
import _root_.scala.Predef._
Pierwsze dwa udostępniają tylko klasy i obiekty singletonowe. Trzeci zawiera wszystkie niejawne konwersje i importowane metody, ponieważ Predef
jest to sam obiekt.
Zaglądając do środka Predef
szybko pokaż kilka symboli:
class <:<
class =:=
object <%<
object =:=
Każdy inny symbol zostanie udostępniony w drodze domniemanej konwersji . Wystarczy spojrzeć na metody oznaczone implicit
tym parametrem i otrzymać jako parametr obiekt typu odbierający metodę. Na przykład:
"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter
W powyższym przypadku ->
jest definiowany w klasie ArrowAssoc
za pomocą metody, any2ArrowAssoc
która przenosi obiekt typu A
, gdzie A
jest parametr typu nieograniczony dla tej samej metody.
Wspólne metody
Tak więc wiele symboli jest po prostu metodami w klasie. Na przykład jeśli tak
List(1, 2) ++ List(3, 4)
Metodę znajdziesz ++
bezpośrednio w ScalaDoc for List . Istnieje jednak jedna konwencja, o której należy pamiętać podczas wyszukiwania metod. Metody kończące się na dwukropek ( :
) wiążą się z prawej zamiast lewej. Innymi słowy, podczas gdy powyższe wywołanie metody jest równoważne z:
List(1, 2).++(List(3, 4))
Gdybym miał, 1 :: List(2, 3)
to byłoby to równoważne z:
List(2, 3).::(1)
Musisz więc spojrzeć na typ znaleziony po prawej stronie , szukając metod kończących się dwukropkiem. Zastanów się na przykład:
1 +: List(2, 3) :+ 4
Pierwsza metoda ( +:
) wiąże się po prawej stronie i znajduje się na List
. Druga metoda ( :+
) jest po prostu normalną metodą i wiąże się w lewo - ponownie, dalej List
.
Cukry syntaktyczne / skład
Oto kilka cukrów składniowych, które mogą ukryć metodę:
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
Ostatni jest interesujący, ponieważ dowolną metodę symboliczną można połączyć, aby w ten sposób utworzyć metodę podobną do przypisania.
I oczywiście w kodzie mogą występować różne kombinacje:
(_+_) // 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.