zoukankan      html  css  js  c++  java
  • <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.
  • 相关阅读:
    国密SM4,javaScript加密 java解密
    使用Nexus搭建Maven私服
    eclipse中使用Maven创建Web项目
    mysql报错码code=exited,status=2的解决方案
    Git出现 fatal: Pathspec 'xxx' is in submodule 'xxx' 异常的解决方案
    php使用ZipArchive提示Fatal error: Class ZipArchive not found in的解决方法
    (转)Git操作
    apt update时出现签名无法验证,公钥失效的解决办法
    提交项目到Github
    分解关联查询
  • 原文地址:https://www.cnblogs.com/wttttt/p/7466259.html
Copyright © 2011-2022 走看看