<Scala><For beginners>

Scala Overview

Scala is object-oriented

  • Every user-defined class in Scala implicitly extends the trait scala.ScalaObject.
  • If Scala is used in the context of a Java runtime environment, then scala.AnyRef corresponds to java.lang.Object.

Scala is Functional

Anonymous Function Syntax

  • eg: 
    (x: Int) => x + 1
    This is a shorthand for the following anonymous class definition:
    new Function1[Int, Int] {
      def apply(x: Int): Int = x + 1
    }
  • It is also possible to define functions with multiple parameters:

    (x: Int, y: Int) => "(" + x + ", " + y + ")"
    
  • or even with no parameter:

    () => { System.getProperty("user.dir") }

Higher-Order Functions

  • Higher-order functions are those who can take functions as parameters, or whose result is a function.
  • Eg: Function apply which takes another function f and a value v and applies function f to v:
    def apply(f: Int => String, v: Int) = f(v)
  • A more complicated example:
    class Decorator(left: String, right: String) {
      def layout[A](x: A) = left + x.toString() + right
    }
    
    object FunTest extends Application {
      def apply(f: Int => String, v: Int) = f(v)
      val decorator = new Decorator("[", "]")
      println(apply(decorator.layout, 7))
    }

  In this example, the method decorator.layout is coerced automatically to a value of type Int => String as required by method apply. Please note that the method decorator.layout is a polymorphic method(i.e. it abstracts over some of its signature types) and the Scala compiler has to instantiate its method type first appropriately.

Nested Functions

  • In Scala it is possible to nest function definitions.
  • Eg:
    object FilterTest extends Application {
      def filter(xs: List[Int], threshold: Int) = {
        def process(ys: List[Int]): List[Int] =
          if (ys.isEmpty) ys
          else if (ys.head < threshold) ys.head :: process(ys.tail)
          else process(ys.tail)
        process(xs)
      }
      println(filter(List(1, 9, 2, 8, 3, 7, 4), 5))
    }

Currying

  • Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments.
  • Eg:
    object CurryTest extends Application {
      def filter(xs: List[Int], p: Int => Boolean): List[Int] =
      	if (xs.isEmpty) xs
      	else if (p(xs.head)) xs.head :: filter(xs.tail, p)
      	else filter(xs.tail, p)
      
      def modN(n: Int)(x: Int) = ((x % n) == 0)
      
      val nums = List(1, 2, 3, 4, 5, 6, 7, 8)
      println(filter(nums, modN(2)))
      println(filter(nums, modN(3)))
    }
    

    Note that method modN is partially applied in the two filter calls; i.e. only its first argument is actually applied. The term modN(2) yields a function of type Int => Boolean and is thus a possible candidate for the second argument of function filter.

Case Classes

    • Case classes are regular classes which export their constructor parameters and which provide a recursive decomposition mechanism via pattern matching.
    • An example for a class hierarchy which consists of an abstract super class Term and three concrete case classes Var, Fun and App.
      abstract class Term
      case class Var(name: String) extends Term
      case class Fun(arg: String, body: Term) extends Term
      case class App(f: Term, v: Term) extends Term
    • This class hierarchy can be used to represent terms of the untyped lambda calculus.
    • To facilitate the construction of case class instances, Scala does not require that the new primitive is used.
    • The main benefits of case class:
      • Dont need new when initialization;
      • better toString() method;
      • with equals() & hashCode() default;
      • with Serializable default;
      • The constructor parameters are public(can be access directly);
      • Support pattern matching;(It makes only sense to define case classes if pattern matching is used to decompose data stuctures.)
    • For better understanding of case class, u should know pattern matching first:
      • For javaer, switch is some kind of pm, but it's easy for programmer to forget 'break';
      • But in scala: [Scala has a built-in general pattern matching mechanism. It allows to match on any sort of data with a first-match policy. ]
        object PatternMatchingTest extends App {
          for (i <- 1 to 100) {
            i match {
              case 10 => println(10)
              case 50 => println(50)
              case _ =>
            }
          }
        }

Case class can be seen as a special class that have been optimized for pattern matching

      .
abstract class Person

case class Student(name: String, age: Int, studentNo: Int) extends Person
case class Teacher(name: Stirng, age: Int, teacherNo: Int) extends Person
case class Nobody(name: String) extends Person

object CaseClassDemo {
  def main(agrs: Array[String]): Unit = {
 	// case class will generate apply method, this can reduce 'new'
    val p: Person = Student("john", 18, 1024)
    
    // match case
    p match {
      case Student(name, age, studentNo) => println(name + ":" + age + ":" + studentNo)
      case Teacher(name,age,teacherNo)=>println(name+":"+age+":"+teacherNo)
      case Nobody(name)=>println(name)
    }
  }
}

当一个类被声明为case class时,scala会帮我们做以下几件事情:

    • 自动创建伴生对象,同时在其内实现子apply方法,因为在使用时不用显式new;
    • 伴生对象内同时实现了upapply(),从而可以将case class用于模式匹配,具体之后在extractor会介绍;
    • 实现toString(), hashCode(), copy(), equals()

Extractor Objects

    • In scala, patterns can be defined independently of case classess. To this end, a method named unapply is defined to yield a so-called extractor.
    • For instance, the following code defines an extractor object `Twice`.
object Twice {
  def apply(x: Int): Int = x * 2
  def unapply(z: Int): Option[Int] = if (z % 2) == 0 Some(z / 2) else None
}

object TwiceTest extends Application {
  val x = Twice(21)
  x match { case Twice(n) => Console.println(n) }
}

There are two syntactic conventions at work here:

    • The pattern case Twice(n) will cause an invocation of Twice.unapply, which is used to match even number; the return value of the unapply signals whether the argument has matched or not, and any sub-values that can be used for further matching. Here, the sub-value is z/2.
    • The apply method is not necessary for pattern matching. It is only used to mimick a constructor. val x = Twice(21) expands to val x = Twice.apply(21).
  • The return type of an unapply should be chosen as follows:
    • If it is just a test, return a Boolean.
    • If it returns a single sub-value of type T, return a Option[T].
    • If u want to return several sub-values T1, ..., Tn, group them in an optional tuple Option[(T1, ..., Tn)].
  • Extractor: 提取器是从传递给它的对象中提取出构造该对象的参数。Scala提取器是一个带有unapply方法的对象。unapply方法算是apply方法的反向操作:unapply方法接受一个对象,然后从对象中提取值,提取的值通常是用来构造该对象的值

Scala is statically typed

  • Scala is equipped with an expressive type system that enforces statically that abstractions are used in a safe and coherent manner. 
  • In particular, the type system supports:
    • generic classes
    • variance annotations
    • upper and lower type bounds
    • inner classes and abstract types as object members
    • compound types
    • explicitly typed self references
    • vies
    • polymorphic methods

Generic classes

  • Scala has built-in support for classes parameterized with types. Such generic classes are particularly useful for the development of collection classes.
  • Eg:
    class Stack[T] {
      var elems: List[T] = Nil
      def push(x: T) { elems = x :: elems }
      def top: T = elems.head
      def pop() { elems = elems.tail }
    }
    

    The use of type parameters allows to check that only legal elements(that of type T) are pushed onto the stack.

  • Note that subtyping of generic types is invariant. This means that if we have a stack of characters of type Stack[Char] then it cannot be used as an integer stack of type Stack[Int]. 

Variances

  • Scala supports variance annotations of type parameters of generic classes.
原文地址:https://www.cnblogs.com/wttttt/p/7466259.html