What do all of Scala's symbolic operators mean?

Scala syntax has a lot of symbols. Since these kinds of names are difficult to find using search engines, a comprehensive list of them would be helpful.

What are all of the symbols in Scala, and what does each of them do?

In particular, I'd like to know about -> , ||= , ++= , <= , _._ , :: , and :+= .


I divide the operators, for the purpose of teaching, into four categories :

  • Keywords/reserved symbols
  • Automatically imported methods
  • Common methods
  • Syntactic sugars/composition
  • It is fortunate, then, that most categories are represented in the 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
    

    The exact meaning of most of these methods depend on the class that is defining them. For example, <= on Int means "less than or equal to". The first one, -> , I'll give as example below. :: is probably the method defined on List (though it could be the object of the same name), and :+= is probably the method defined on various Buffer classes.

    So, let's see them.

    Keywords/reserved symbols

    There are some symbols in Scala that are special. Two of them are considered proper keywords, while others are just "reserved". They are:

    // 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
    

    These are all part of the language, and, as such, can be found in any text that properly describe the language, such as Scala Specification(PDF) itself.

    The last one, the underscore, deserve a special description, because it is so widely used, and has so many different meanings. Here's a sample:

    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
    

    I probably forgot some other meaning, though.

    Automatically imported methods

    So, if you did not find the symbol you are looking for in the list above, then it must be a method, or part of one. But, often, you'll see some symbol and the documentation for the class will not have that method. When this happens, either you are looking at a composition of one or more methods with something else, or the method has been imported into scope, or is available through an imported implicit conversion.

    These can still be found on ScalaDoc: you just have to know where to look for them. Or, failing that, look at the index (presently broken on 2.9.1, but available on nightly).

    Every Scala code has three automatic imports:

    // Not necessarily in this order
    import _root_.java.lang._      // _root_ denotes an absolute path
    import _root_.scala._
    import _root_.scala.Predef._
    

    The first two only make classes and singleton objects available. The third one contains all implicit conversions and imported methods, since Predef is an object itself.

    Looking inside Predef quickly show some symbols:

    class <:<
    class =:=
    object <%<
    object =:=
    

    Any other symbol will be made available through an implicit conversion. Just look at the methods tagged with implicit that receive, as parameter, an object of type that is receiving the method. For example:

    "a" -> 1  // Look for an implicit from String, AnyRef, Any or type parameter
    

    In the above case, -> is defined in the class ArrowAssoc through the method any2ArrowAssoc that takes an object of type A , where A is an unbounded type parameter to the same method.

    Common methods

    So, many symbols are simply methods on a class. For instance, if you do

    List(1, 2) ++ List(3, 4)
    

    You'll find the method ++ right on the ScalaDoc for List. However, there's one convention that you must be aware when searching for methods. Methods ending in colon ( : ) bind to the right instead of the left. In other words, while the above method call is equivalent to:

    List(1, 2).++(List(3, 4))
    

    If I had, instead 1 :: List(2, 3) , that would be equivalent to:

    List(2, 3).::(1)
    

    So you need to look at the type found on the right when looking for methods ending in colon. Consider, for instance:

    1 +: List(2, 3) :+ 4
    

    The first method ( +: ) binds to the right, and is found on List . The second method ( :+ ) is just a normal method, and binds to the left -- again, on List .

    Syntactic sugars/composition

    So, here's a few syntactic sugars that may hide a method:

    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
    

    The last one is interesting, because any symbolic method can be combined to form an assignment-like method that way.

    And, of course, there's various combinations that can appear in 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.
    

    One (good, IMO) difference between Scala and other languages is that it lets you name your methods with almost any character.

    What you enumerate is not "punctuation" but plain and simple methods, and as such their behavior vary from one object to the other (though there are some conventions).

    For example, check the Scaladoc documentation for List, and you'll see some of the methods you mentioned here.

    Some things to keep in mind:

  • Most of the times the A operator+equal B combination translates to A = A operator B , like in the ||= or ++= examples.

  • Methods that end in : are right associative, this means that A :: B is actually B.::(A) .

  • You'll find most answers by browsing the Scala documentation. Keeping a reference here would duplicate efforts, and it would fall behind quickly :)


    You can group those first according to some criteria. In this post I will just explain the underscore character and the right-arrow.

    _._ contains a period. A period in Scala always indicates a method call . So left of the period you have the receiver, and right of it the message (method name). Now _ is a special symbol in Scala. There are several posts about it, for example this blog entry all use cases. Here it is an anonymous function short cut , that is it a shortcut for a function that takes one argument and invokes the method _ on it. Now _ is not a valid method, so most certainly you were seeing _._1 or something similar, that is, invoking method _._1 on the function argument. _1 to _22 are the methods of tuples which extract a particular element of a tuple. Example:

    val tup = ("Hallo", 33)
    tup._1 // extracts "Hallo"
    tup._2 // extracts 33
    

    Now lets assume a use case for the function application shortcut. Given a map which maps integers to strings:

    val coll = Map(1 -> "Eins", 2 -> "Zwei", 3 -> "Drei")
    

    Wooop, there is already another occurrence of a strange punctuation. The hyphen and greater-than characters, which resemble a right-hand arrow , is an operator which produces a Tuple2 . So there is no difference in the outcome of writing either (1, "Eins") or 1 -> "Eins" , only that the latter is easier to read, especially in a list of tuples like the map example. The -> is no magic, it is, like a few other operators, available because you have all implicit conversions in object scala.Predef in scope. The conversion which takes place here is

    implicit def any2ArrowAssoc [A] (x: A): ArrowAssoc[A] 
    

    Where ArrowAssoc has the -> method which creates the Tuple2 . Thus 1 -> "Eins" is actual the call Predef.any2ArrowAssoc(1).->("Eins") . Ok. Now back to the original question with the underscore character:

    // lets create a sequence from the map by returning the
    // values in reverse.
    coll.map(_._2.reverse) // yields List(sniE, iewZ, ierD)
    

    The underscore here shortens the following equivalent code:

    coll.map(tup => tup._2.reverse)
    

    Note that the map method of a Map passes in the tuple of key and value to the function argument. Since we are only interested in the values (the strings), we extract them with the _2 method on the tuple.

    链接地址: http://www.djcxy.com/p/2000.html

    上一篇: 什么是副本

    下一篇: 斯卡拉的所有符号运算符是什么意思?