В целях обучения я делю операторов на четыре категории :
- Ключевые слова / зарезервированные символы
- Автоматически импортированные методы
- Общие методы
- Синтаксические сахара / состав
К счастью, в этом вопросе представлено большинство категорий:
-> // 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
Точное значение большинства этих методов зависит от класса, который их определяет. Например, <=
на Int
означает «меньше или равно» . Первый ->
, я приведу в качестве примера ниже. ::
Вероятно, это метод, определенный в List
(хотя это может быть объект с тем же именем), и :+=
, вероятно, метод, определенный в различных Buffer
классах.
Итак, давайте посмотрим на них.
Ключевые слова / зарезервированные символы
В Scala есть специальные символы. Два из них считаются правильными ключевыми словами, а другие просто «зарезервированы». Они есть:
// 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
Все они являются частью языка и, как таковые, могут быть найдены в любом тексте, который правильно описывает язык, например, в самой спецификации Scala (PDF).
Последнее, подчеркивание, заслуживает особого описания, потому что оно очень широко используется и имеет так много разных значений. Вот пример:
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
Я, наверное, забыл какой-то другой смысл, хотя.
Автоматически импортированные методы
Итак, если вы не нашли символ, который ищете в списке выше, то это должен быть метод или его часть. Но часто вы увидите какой-нибудь символ, и документация для класса не будет иметь этого метода. Когда это происходит, либо вы просматриваете композицию одного или нескольких методов с чем-то другим, либо метод был импортирован в область действия или доступен через импортированное неявное преобразование.
Их все еще можно найти в ScalaDoc : вам просто нужно знать, где их искать. Или, если это не удалось, посмотрите на индекс (в настоящее время не работает на 2.9.1, но доступен на ночной).
Каждый код Scala имеет три автоматических импорта:
// Not necessarily in this order
import _root_.java.lang._ // _root_ denotes an absolute path
import _root_.scala._
import _root_.scala.Predef._
Первые два делают доступными только классы и одноэлементные объекты. Третий содержит все неявные преобразования и импортированные методы, поскольку Predef
является самим объектом.
Заглянув внутрь, Predef
быстро покажите несколько символов:
class <:<
class =:=
object <%<
object =:=
Любой другой символ будет доступен через неявное преобразование . Достаточно взглянуть на методы, помеченные этим, implicit
которые получают в качестве параметра объект типа, который получает метод. Например:
"a" -> 1 // Look for an implicit from String, AnyRef, Any or type parameter
В приведенном выше случае ->
определяется в классе с ArrowAssoc
помощью метода, any2ArrowAssoc
который принимает объект типа A
, где A
параметр неограниченного типа для этого же метода.
Общие методы
Итак, многие символы - это просто методы класса. Например, если вы делаете
List(1, 2) ++ List(3, 4)
Вы найдете этот метод ++
прямо в ScalaDoc for List . Однако есть одно соглашение, которое вы должны знать при поиске методов. Методы, оканчивающиеся на двоеточие ( :
), связываются справа, а не слева. Другими словами, хотя приведенный выше вызов метода эквивалентен:
List(1, 2).++(List(3, 4))
Если бы я имел вместо этого 1 :: List(2, 3)
, это было бы эквивалентно:
List(2, 3).::(1)
Поэтому вам нужно взглянуть на тип, найденный справа, при поиске методов, заканчивающихся двоеточием. Рассмотрим, например:
1 +: List(2, 3) :+ 4
Первый метод ( +:
) привязывается вправо и находится на List
. Второй метод ( :+
) является обычным методом и привязывается слева - опять же, вкл List
.
Синтаксические сахара / состав
Итак, вот несколько синтаксических сахаров, которые могут скрывать метод:
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
Последний интересен, потому что любой символический метод может быть объединен таким образом, чтобы сформировать метод, подобный присвоению.
И, конечно же, в коде могут появляться различные комбинации:
(_+_) // 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.