Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、

时间:2022-05-06
本文章向大家介绍Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1:Scala和Java的对比:

1.1:Scala中的函数是Java中完全没有的概念。因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只有方法的概念,即寄存和依赖于类与对象中的方法。Java中的方法是绝对不可能脱离类和对象独立存在的。
1.2:Scala是一门既面向对象,又面向过程的语言。因此在Scala中有非常好的面向对象的特性,可以使用Scala来基于面向对象的思想开发大型复杂的系统和工程,而且Scala也面向过程,因此Scala中有函数的概念。在Scala中,函数和类,对象等一样,都是一等公民。Scala中的函数可以独立存在,不需要依赖于任何类与对象。
1.3:Scala的函数式编程,就是Scala面向过程的最好的佐证。也正是因为函数式编程,才让Scala具备了Java所不具备对的更强大的功能和特性。
    而之所以Scala一直没有替换Java,是因为Scala之前一直没有开发过太多知名的应用。而Java则不一样。最重要的一点在于,Java现在不只是一门编程语言,还是一个庞大的,涵盖了软件开发,甚至云计算,大数据的技术生态。其中重要框架和系统包含Spring,lucene,Hadoop,Activiti等等。

2:Scala之函数式编程:

2.1:将函数赋值给变量:
    Scala中的函数是一等公民,可以独立定义,独立存在,而且可以直接将函数作为值赋值给变量,必须在函数后面加上空格和下划线:
    class Person{

      def hello(name : String) = {
        println("hi," + name)
      }
      //将函数赋值给变量的语法,函数命令 _(1、函数名称,2、空格,3、下划线)
      val sayHello = hello _;
      sayHello("张三");
    }
    //定义一个Object来测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p1 = new Person;
        p1.sayHello
      }
    }
2.2:匿名函数:
    Scala中,函数也可以不需要命名,此时函数被称为匿名函数。可以直接定义函数之后,将函数赋值给某个变量,也可以将直接定义的匿名函数传入其他函数之中。Scala定义匿名函数的语法规则就是:(参数名称:参数类型) => 函数体;这种语法必须掌握和深刻理解。
    class Person{

      val sayHello = (name : String) => println("hi,"+ name);
    }
    //定义一个Object来测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p1 = new Person;
        p1.sayHello("张三");
      }
    }
2.3:高阶函数:
    Scala中,由于函数是一等公民,因此可以直接将某个函数传入其他函数,作为参数。这个功能是及其强大的,也是Java这种面向对象的编程语言所不具备的。
    接受其他函数作为参数的函数,也被称作为高阶函数(higher-order function),高阶函数的另一个功能就是将函数作为返回值:
    class Person{

      val sayHello = (name : String) => println("hi,"+ name);
      //def 函数名称(函数名称:(函数类型) => 函数返回值,参数1 :参数类型......)
      def greeting(hello:(String) => Unit, name: String): Unit ={
        hello(name);
      }
    }
    //定义一个Object来测试        
    object Object {

      def main(args: Array[String]): Unit = {
        val p1 = new Person;
        p1.greeting(p1.sayHello, "李思思");
      }
    }
    //高阶函数的另一个功能就是将函数作为返回值:
    class Person{
      //高阶函数的另一个功能就是将函数作为返回值:
      def getGreetingFunc(msg : String) = (name : String) => println(msg +", " + name);
      val greetingFunc = getGreetingFunc("hello");
      greetingFunc("张三三");
    }
    //定义一个Object来测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p1 = new Person;
        p1.greetingFunc;
        println(Array(1,2,3,4,5).map((num : Int) => num * num).toBuffer)
      }
    }
2.4:高阶函数的类型推断:
    高阶函数可以自动推断出参数类型,而不需要写明类型,而且对于只有一个参数的函数,还可以省去其小括号。如果仅有一个参数在右侧的函数体内只使用一次,则还可以将接受参数省略,并且将参数用_来替代。
    class Person{

      //func函数名称作为参数一。name是参数二
      def greeting(func:(String) => Unit,name : String) {
        func(name)
      }
      //匿名函数
      greeting((name : String) => println("hello," + name) ,"张三");
      //高阶函数可以自动推断出参数类型,而不需要写明类型。如这里没有写name的String类型。
      greeting((name) => println("hello, "+ name) ,"李思思");
      //而且对于只有一个参数的函数,还可以省去其小括号。
      greeting(name => println("hello," + name) ,"王五五");

      //如果仅有一个参数在右侧的函数体内只使用一次,则还可以将接受参数省略,并且将参数用_来替代。
      def triple(func:(Int) =>Int) ={
        func(3)
      }

    }
    //定义一个Object来测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p1 = new Person;
        println(p1.triple(10 * _))
      }
    }
2.5:Scala的常用的高阶函数:
    a、map,对传入的每个元素都进行映射,返回一个处理后的元素:
        println(Array(1,2,3,4,5).map(2 * _).toBuffer);
    b、foreach,对传入的每个元素都进行处理,但是没有返回值:
        (1 to 9).map("*" * _).foreach(println _);
    c、filter,对传入的每个元素都进行条件判断,如果对元素返回true,则保留该元素,否则过滤掉该元素:
        val a = (1 to 20).filter(_ % 2 ==0);
        println(a)
    d、reduceLeft,从左侧元素开始,进行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,再将结果与元素4处理,依次类推,即为reduce:
        var a = (1 to 9).reduceLeft(_ * _);
        //此操作相当于1*2*3*4*5*6*7*8*9
        println(a)
    e、sortWith,对元素进行两两相比,进行排序:
        var arr = Array(3,2,4,1,5,7).sortWith(_ < _);
        println(arr.toBuffer)
2.6:闭包:
    a、在Java中,不支持直接将函数传入一个方法作为参数,通常来说,唯一的方法就是定义一个实现了某个接口的类的实例对象,该对象只有一个方法。而这些接口都只有单个的抽象方法,也就是single abstract method,简称为SAM;
    b、由于Scala是可以调用Java的代码的,因此当我们调用Java的某个方法的时候,可能就不得不创建SAM传递给方法,非常麻烦。但是Scala又是直接传递函数的。此时就可以使用Scala提供的,在调用Java方法的时候,使用的功能。SAM转换,即将SAM转换为Scala函数。(注意:要使用SAM转换为,需要使用Scala提供的特性,隐式转换):
    c、闭包,最简洁的解释就是函数在变量不处于其有效作用域的时候,还能够对变量进行访问,即为闭包;
        class Person{

          def getGreetingFunc(msg : String) = (name : String) => println(msg + "," + name);
          //两次调用getGreetingFunc函数,传入不同的msg,并创建不同的函数返回.
          //然而,msg只是一个局部变量,却在getGreetingFunc执行完以后,还可以继承存在创建的函数之中。
          //greetingFuncHello("张三"),调用的时候,值为"hello"的msg被保留在了函数体内部,可以反复的使用。
          //这种变量超出了其作用域,还可以使用的情况,即为闭包。

          val greetingFuncHello = getGreetingFunc("hello");
          val greetingFuncHi = getGreetingFunc("hi");
          //Scala通过为每个函数创建对象来实现闭包,实际上对于getGreetingFunc函数创建的函数。msg是作为函数对象的变量存在的。因此每个函数才可以拥有不同的msg
          //Scala编译器会确保上述闭包机制。

        }
        //定义一个Object来测试
        object Object {

          def main(args: Array[String]): Unit = {
            val p1 = new Person;
            p1.greetingFuncHello("张三三");
            p1.greetingFuncHi("李思思");
          }
        }
2.7:SAM转换(Scala函数和Java的类转换):
  a、在Java中,不支持直接将函数传入一个方法作为参数,通常来说,唯一的方法就是定义一个实现了某个接口的类的实例对象,该对象只有一个方法。而这些接口都只有单个的抽象方法,也就是single abstract method,简称为SAM;
    b、由于Scala是可以调用Java的代码的,因此当我们调用Java的某个方法的时候,可能就不得不创建SAM传递给方法,非常麻烦。但是Scala又是直接传递函数的。此时就可以使用Scala提供的,在调用Java方法的时候,使用的功能。SAM转换,即将SAM转换为Scala函数。(注意:要使用SAM转换为,需要使用Scala提供的特性,隐式转换): 
2.8:Currying函数:
  Currying函数指的是,将原来接受两个参数的一个函数,转换为两个函数,第一个函数接受原先的第一个参数,然后返回接受原先第二个参数的第二个函数。在函数调用的过程中,就变为了两个函数连续调用的形式:
    class Person{

      def sum(a: Int ,b : Int) = a + b;
      def sum2(a : Int) = (b : Int) => a+b;
      def sum3(a : Int)(b : Int) = a + b;
    }
    //定义一个Object来测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p = new Person;
        println(p.sum(1,4));
        println(p.sum2(2)(2));
        println(p.sum3(3)(3));
      }
    }
2.9:return:
  Scala中,不需要使用return来返回函数的值,函数最后一行语句的值,就是函数的返回值。在Scala中,return用于在匿名函数中返回值给包含匿名函数的带名函数,并作为带名函数的返回值。使用return的匿名函数,是必须给出返回类型的,否则无法通过编译。
    class Person{

      def greeting(name : String) ={
        def hello(name : String): String ={
           return "hello," + name;
        }
        hello(name);
      }
    }        
    //定义一个Object来测试    
    object Object {

      def main(args: Array[String]): Unit = {
        val p = new Person;
        println(p.greeting("李思思"));
      }
    }

3:Scala函数式编程之集合操作:

3.1:Scala的集合体系结构:
    Scala中的集合体系主要包括:Iterable,Seq,Set,Map。其中,Iterable是所有集合trait的跟trait。这个结构与Java的集合体系非常相似。
    Scala中的集合是分成可变和不可变的两类集合的,其中可变集合就是说,集合的元素可以动态修改。而不可变集合的元素在初始化之后,就无法修改了。分别对应scala.collection.mutable和scala.collection.immutable两个包。
    Scala中的Seq下包含了Range,ArrayBuffer,List等子trait。其中Range就代表了一个序列,通常可以使用"1 to 10"这种语法来产生一个Range。ArrayBuffer就类似于Java中的ArrayList。
    Scala的集合类的map,flatMap,reduce,reduceLeft,foreach,等这些函数就是高阶函数。可以接受其他函数作为参数。
3.2:List:
    List代表一个不可变的列表,List的创建,val list = new List(1,2,3,4);List有head和tail,head代表List的第一个元素,tail代表第一个元素以后的所有元素。list.head,list.tail;
    List有特殊的::操作符,可以用于将head和tail合并成一个List,0::list;
    
3.3:LinkedList:
    LinkedList代表一个可变的列表,使用elem可以引用其头部,使用next可以引用其尾部。
    val l = mutable.LinkedList(1,2,3,4,5,6,7);
    println(l.elem + " " + l.next);
3.4:Set:
    Set代表一个没有重复元素的集合。将重复元素加入Set是没有用的。而且Set是不保证插入顺序的,也就是说,Set中的元素是乱序的。LinkedHashSet会用一个链表来维护插入顺序。SortedSet会自动根据key来进行排序的。
    
3.5:集合的函数式编程:
    a、map案例,为List中每个元素都添加一个前缀:
        val list = List("张三","李思思","王五五").map("name is :" + _);
        println(list.toBuffer)
    b、faltMap案例,将List中的多行句子拆分成单词:
        val list = List("hello world , i am bie xiansheng").flatMap(_.split(" "));
        println(list.toBuffer)
    c、foreach案例,打印List中的每个单词:
        List("hello world , i am bie xiansheng").foreach(println(_));
    d、zip案例,对学生姓名和学生成绩进行关联:
        val list = List("张三三","李思思","王五五","赵六六").zip(List("1","2","3","4"));
        println(list)

 4:Scala之模式匹配(mathch case语法,即为模式匹配):

模式匹配是Scala中非常有特色的,非常强大的一种功能。模式匹配,其实类似于Java中的swich case语法,即对一个值进行条件判断,然后针对某种条件,即针对不同的处理。但是Scala的模式匹配功能比Java的swich case语法的功能强大的多,Java的swich case语法只能对值进行匹配。但是Scala的模式匹配除了可以对值进行匹配之外,还可以对类型进行匹配,对Array和List的元素情况进行匹配,对case class进行匹配,甚至对有值或者没值进行匹配。

4.1:模式匹配的基础语法:
    a、mathch case的语法如下所示:变量 mathch {case 值 => 语法}。如果值为下划线,则代表了不满足以上所有情况下的默认情况如何处理。此外,match case中,主要一个case分支满足并处理了,就不会继续判断下一个case的分支了。(区别Java的break;)
    object Object {

      def main(args: Array[String]): Unit = {
        def judgeGeade(grade : String): Unit ={
          grade match {
            case "A" => println("A");
            case "B" => println("B");
            case "C" => println("C");
            case "D" => println("D");
            case _   => println("没有默认匹配的")
          }
        }
        judgeGeade("A");
        judgeGeade("E");
      }
    }
    b、模式匹配中使用if守卫:
        Scala的模式匹配语法,有一个特点在于,可以在case后的条件判断中,不仅仅只是提供一个值,而是可以在值的后面再加一个if守卫,进行双重过滤:        
    object Object {

      def main(args: Array[String]): Unit = {
        def judgeGeade(name : String ,grade : String): Unit ={
          grade match {
            case "A" => println(name + "A");
            case "B" => println(name +" B");
            case "C" => println(name +" C");
            case "D" => println(name +" D");
            case _ if name == "张三三" => println(name + ",you are luck boy!");
            case _   => println("没有默认匹配的")
          }
        }
        judgeGeade("张三三","A");
      }
    }
    c、在模式匹配中进行变量赋值:
        Scala的模式匹配语法中,有一个特点在于,可以将模式匹配的默认情况,下划线,替换为一个变量名,此时模式匹配语法就会将要匹配的值赋值给这个变量,从而可以在后面的处理语句中使用要匹配的值:
        优点:可以显示出_grade的值;
    object Object {

      def main(args: Array[String]): Unit = {
        def judgeGeade(name : String ,grade : String): Unit ={
          grade match {
            case "A" => println(name + "A");
            case "B" => println(name +" B");
            case "C" => println(name +" C");
            case "D" => println(name +" D");
            case _grade if name == "张三三" => println(name + ",you are luck boy!" + _grade);
            case _   => println("没有默认匹配的")
          }
        }
        judgeGeade("张三三","E");
      }
    }
4.2:对类型进行模式匹配:
    Scala的模式匹配一个强大之处就在于,可以直接匹配类型,而不是值。
    object Object {

      def main(args: Array[String]): Unit = {
        def processException(e : Exception): Unit ={
          e match {
            case e1 : IllegalArgumentException => println("IllegalArgumentException" + e1);
            case e2 : FileNotFoundException => println("FileNotFoundException" + e2);
            case e3 : IndexOutOfBoundsException => println("IndexOutOfBoundsException" + e3);
            case _ : Exception => println("Exception");
          }
        }
        processException(new IllegalArgumentException());
      }
    }
4.3:对Array和List的元素进行模式匹配:
    对Array进行模式匹配,分别可以匹配带有指定元素的数组,带有指定个数元素的数组,以某元素打头的数组。
    对List进行模式匹配,与Array类似,但是需要使用List特有的::操作符;
    object Object {

      def main(args: Array[String]): Unit = {
        def greeting(arr : Array[String]): Unit ={
          arr match {
            case Array("张三三") => println("hi,张三三");
            case Array(a,b,c,d) => println("hi," + a +" ,"+ b + ", " + c + " ,"+ d);
            case Array("李思思",_*) => println("hi,李思思");
            case _ => println("hi,how are you.")
          }
        }
        greeting(Array("张三三","李思思","王五五","a","b","c","d"));
        greeting(Array("李思思"));
        greeting(Array("a","b","c","d"));
      }
    }
    //使用List来进行模式匹配;
    object Object {

      def main(args: Array[String]): Unit = {
        def greeting(list : List[String]): Unit ={
          list match {
            case "张三三" :: Nil => println("hi,张三三");
            case a :: b :: c :: d => println("hi,"+ a +" ,"+ b + ", " + c + " ,"+ d);
            case "李思思" :: tail => println("hi,李思思");
            case _ => println("hi,how are you.")
          }
        }
        greeting(List("张三三"));
        greeting(List("李思思"));
        greeting(List("王五五"));

      }
    }
4.4:case class与模式匹配:
    Scala中提供了一种特殊的类,用case class进行声明,中文也可以称做样例类。case class其实有点类似于Java中的JavaBean的概念。即只定义field,并且由Scala编译时自动提供getter和setter方法,但是没有method。case calss的主构造函数接受的参数通常不需要使用var或者val修饰,scala自动就会使用val修饰,但是如果你自己使用var修饰,name还是会按照var来。Scala自动为case class定义了伴生对象,也就是Obeject,并且定义了apply()方法,该方法接受主构造函数中相同的参数,并且返回case class对象。    
    case class Student(name : String,classroom : String) extends Person{

    }
    case class Teacher(name : String,subject : String) extends  Person {

    }
    class Person{

      def judge(p : Person): Unit ={
        p match {
          case Teacher(name,subject) => println("teacher ,name is: "+ name +",subject is :" +subject)
          case Student(name,classroom) => println("student,name is: " + name +", classroot is :" + classroom);
          case _ => println("illegal access,please go out of the school")
        }
      }
    }
    //定义一个Object
    object Object {

      def main(args: Array[String]): Unit = {
        val zhangsan : Person = Teacher("张三三","语文");
        val lisisi : Person = Teacher("李思思","数学");

        val wangwu : Person = Student("王五五","一年级");
        val person = new Person;
        person.judge(zhangsan);
        person.judge(lisisi);
        person.judge(wangwu);
      }
    }

4.5:Option与模式匹配:
    Scala有一种特殊的类型,叫做Option。Option有两种值,一种是Some,表示有值,一种是None,表示没有值。Option通常会用于模式匹配中,用于判断某个变量是有值还是没有值,这比null来的更加简明。
    class Person{

      val grades = Map("张三三" -> "A" ,"李思思" -> "B","王五五" -> "C");
      def getGrade(name :String): Unit ={
        val grade = grades.get(name);
        grade match {
          case Some(grade) => println("you grade is : " + grade);
          case None => println("sorry,you grade is null")
        }
      }
    }
    //定义一个Object
    object Object {

      def main(args: Array[String]): Unit = {
        val p = new Person;
        p.getGrade("张三三");
        p.getGrade("李思思");
        p.getGrade("王五五");
        p.getGrade("赵六六");
      }
    }

5:Scala中的类型参数:

其实就是类似于Java中的泛型。也是定义一种类型参数,比如在集合,在类,在函数中,定义类型参数,然后就可以保证使用到该类型参数的地方,就肯定,也只能是这种类型。从而实现程序更好的健壮性。

5.1:泛型类:
    顾名思义,其实就是在类的声明中,定义一些泛型类型,然后在类内部,比如field或者method,就可以使用这些泛型类型。使用泛型类,通常是需要对类中的某些成员,比如某些field或者method中的参数或者变量,进行统一的类型限制,这样可以保证程序更好的健壮性和稳定性。如果不使用泛型进行统一的类型限制,那么在后期程序运行过程中,难免出现问题,比如传入了不希望的类型,导致程序出现问题。在使用类的时候,比如创建类的对象,将类型参数替换为实际的类型,即可。或者直接给使用了泛型类型的field赋值时候,Scala会自动进行类型推断。
    class Person[T](val id : T){

      def getMessage(name : T) ={
        println("id:" + id + ",name:" + name);
      }
    }
    //定义一个Object进行测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p = new Person[String]("1008611");
        p.getMessage("张三三");
      }
    }
5.2:泛型函数:
    泛型函数,与泛型类类似,可以给某个函数在声明的时候指定泛型类型,然后再函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的变量,或者多个变量,进行强制性的类型限制。于泛型类一样,你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型,也可以在调用函数时候,手动指定泛型类型。
    class Person{

      def getCard[T](content : T)={
        if(content.isInstanceOf[Int]){
          println("card:001:" + content );
        }else if(content.isInstanceOf[String]){
          println("card:002:" + content);
        }else{
          println("card:003:" + content)
        }
      }
    }
    //定义一个Object进行测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p = new Person();
        p.getCard("张三三");
        p.getCard(24)
        p.getCard(true)
      }
    }
5.3:上边界Bounds:
    在指定泛型类型的时候,有时候,我们需要对泛型类型的范围进行界定,而不是可以是任意的。比如,我们可能要求某个泛型类型,它就必须是某个类的子类,这样在程序中就可以放心的调用泛型类型继承的父类的方法,程序才能正常的使用和运行。此时就可以使用上下边界Bounds的特性。Scala的上下边界特性允许泛型类型必须是某个类的子类,或者必须是某个类的父类。
    class Person(val name : String){

      def hello = println("hi.i am " + name);
      def makeFriends(p : Person): Unit ={
        hello;
        p.hello
      }
    }
    //定义一个Student继承Person
    class Student(name : String) extends Person(name){


    }
    //定义一个类Party使用上边界
    class Party[T <: Person](p1 : T,p2 : T) {

      //def play = p1.makeFriends(p2);
      def play(): Unit ={
        p1.makeFriends(p2);
      }
    }
    //定义一个Object进行测试
    object Object {

      def main(args: Array[String]): Unit = {
        val s1 = new Student("张三三");
        val s2 = new Student("李思思");

        val p = new Party[Person](s1,s2);
        p.play()
      }
    }
5.4:下边界Bounds:
    除了指定泛型类型的上边界,还可以指定下边界,即指定泛型类型必须是某个类的父类;
    class Father(val name : String) {

    }
    class Child(name : String) extends Father(name){

    }
    //定义一个Object进行测试
    object Object {

      def getIdCard[R >: Child](person : R): Unit ={
        if(person.getClass == classOf[Child]){
          println("请告诉我你爸爸的姓名!")
        }else if(person.getClass == classOf[Father]){
          println("请拿走你孩子的身份证!")
        }else{
          println("你开心就好!")
        }
      }
      def main(args: Array[String]): Unit = {
        val c = new Child("张三三");
        getIdCard(c);
        val f = new Father("李思思");
        getIdCard(f)
      }
    }
5.5:View Bounds:
    上下边界Bounds,虽然可以让一种泛型类型,支持有父子关系的多种类型。但是,在某个类与上下边界Bounds指定的父子类型范围内的类都没有任何关系,则默认是肯定不能接受的。然而,View Bounds作为一种上下边界Bounds的加强版,支持可以对类型进行隐式转换,将指定的类型进行隐式转换后,再判断是否在边界指定的类型范围内:
    class Person(val name : String) {

    }
    class Dog(val name : String) {

      def hello(): Unit ={
        println("汪汪汪汪,i am " + name)
      }
    }
    class Patty[T <% Person](p1 :T,p2 : T) {

      def show(): Unit ={
        println("View Bounds的练习学习")
      }
    }    
    //定义一个Object进行测试
    object Object {

      implicit def dog2Person(dog : Object) : Person ={
        if(dog.isInstanceOf[Dog]){
          val _dog = dog.asInstanceOf[Dog];
          new Person(_dog.name);
        }else{
          null;
        }
      }

      def main(args: Array[String]): Unit = {
        val person = new Person("张三三");
        val dog = new Dog("小旺旺");

        val party = new Patty[Person](person,dog);
        party.show()
      }
    }
5.6:Context Bounds:
    是一种特殊的Bounds,它会根据泛型类型的声明,比如"T : 类型"要求必须存在一个类型为"类型[T]"的隐式值。其实,Context Bounds之所以叫Context,是因为它基于的是一种全局的上下文,需要使用到上下文中的隐式值以及注入。
   
5.7:Manifest Context Bounds:
    在Scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds。也就是说,如果数组元素类型为T的话或者函数定义[T :Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组;
    class Meat(val name : String) {

    }
    class Vegetable(val name : String) {

    }    
    //定义一个Object进行测试
    object Object {

      def foodPackage[T : Manifest](food : T*) ={
        val foodPackage = new Array[T](food.length);
        for(i <- 0 until(food.length)){
          foodPackage(i) = food(i);
        }
        foodPackage;
      }
      def main(args: Array[String]): Unit = {
        val m1 = new Meat("大肉");
        val v1 = new Vegetable("胡萝卜");

        println(foodPackage(m1,v1).toBuffer);
      }
    }
5.8:协变和逆变:
    Scala中的协变和逆变是非常有特色的,解决了Java中的泛型的一大缺憾。比如,Java中,如果有Professional是Master的子类,那么Card[Professional]是不是Card[Master]的子类呢,答案是,肯定不是啊。因此对于发开程序造成了很多的麻烦。而Scala中,只要灵活使用了协变和逆变,就可以解决Java中泛型的问题。
    class Master {

    }
    class Professional extends Master{

    }
    class Card[+T](val name : String) {
      //+是协变
      def enterMeet(card : Card[Master]): Unit ={
        println("欢迎大师以及大师级别以下的来到会场")
      }
    }
    class Card2[-T](val name : String){

      def enterMeet2(card : Card2[Professional]): Unit ={
        println("只有专家级别的才可以进入此会场,如果是大师级别的当然更可以了")
      }
    }
    //定义一个Object进行测试
    object Object {

      def main(args: Array[String]): Unit = {
        val p = new Card[Professional]("张三三专家");
        val m = new Card[Master]("李思思大师");
        p.enterMeet(m);
        m.enterMeet(p);

        val p2 = new Card2[Professional]("张三三专家");
        val m2 = new Card2[Master]("李思思大师");
        p2.enterMeet2(p2);
        p2.enterMeet2(m2);
        m2.enterMeet2(p2);
        m2.enterMeet2(m2);
      }
    }
5.9:Existential Type:
  在Scala里面,有一种特殊的类型参数,就是    Existential Type,即存在性类型。
    Array[T] forSome{type T}
    Array[_]

6:Scala之隐式转换与隐式参数:

  允许手动指定,将某种类型的对象转换成其他类型的对象。最核心的就是定义隐式转换函数,即implicit conversion function。定义的隐式转换函数,只要在编写的程序内引入,就会被Scala自动使用。Scala会根据隐式转换函数的签名,在程序中使用隐式转换函数接受的参数类型定义的对象时,会自动将其传入隐式转换函数,转换为另外一种类型的对象并且返回。这就是"隐式转换";隐式转换函数的名字随便起,因为通常不会由用户手动调用,而是Scala进行调用的。但是如果要使用隐式转换,则需要对隐式转换函数进行导入。因此通常建议将隐式转换函数的名称命名为"one2one"的形式。

6.1:隐式转换:
    实现隐式转换,只要在程序可见的范围内定义隐式转换函数即可。Scala会自动使用隐式转换函数。隐式转换函数与普通函数唯一的语法区别就是,要以implicit开头,而且一定要定义函数返回类型。
    class Student(val name : String) {

    }
    class Older(val name : String) {

    }
    class SpecialPerson(val name : String) {

      var ticketNum = 0;
      def buySpecialTicket(p : SpecialPerson): Unit ={
        ticketNum += 1;
        println("票数:" + ticketNum);
      }
    }
    //定义一个Object来测试
    object Object {

      implicit def object2SpecialPerson(obj : Object) : SpecialPerson = {
        if(obj.getClass == classOf[Student]){
          val s = obj.asInstanceOf[Student];
          new SpecialPerson(s.name);
        }else if(obj.getClass == classOf[Older]){
          val older = obj.asInstanceOf[Older];
          new SpecialPerson(older.name);
        }else{
          null;
        }
      }


      def main(args: Array[String]): Unit = {
        val s = new Student("张三三");
        val o = new Older("李思思");
        val specialPerson = new SpecialPerson("王五五");

        specialPerson.buySpecialTicket(s);
        specialPerson.buySpecialTicket(o);
        specialPerson.buySpecialTicket(specialPerson);
      }
    }
6.2:使用隐式转换加强现有类型:
    隐式转换非常强大的一个功能,就是可以在不知不觉中加强现有类型的功能。也就是说,可以为,某个类定义一个加强版的类,并定义互相之间的隐式转换,从而让源类在使用加强版的方法时,由Scala自动进行隐式转换为加强肋,然后再调用该方法。
    class Man(val name : String) {

    }
    class SuperMan(val name : String) {

      def emitLaser = println(name + " ,变身超人");
    }
    //定义一个Object来测试
    object Object {

      implicit def man2SuperMan(man : Man):SuperMan = new SuperMan(man.name);

      def main(args: Array[String]): Unit = {
        val man = new Man("张三三");
        man.emitLaser;
      }
    }
6.3:导入隐式转换函数(隐式转换函数作用域与导入):
    Scala默认会使用两种隐式转换,一种是源类型,或者目标类型的伴生对象内的隐式转换函数;一种是当前程序作用域内的可以用唯一标识标识的隐式转换函数。如果隐式转换函数不在上述两种情况下的话,那么就必须手动使用import语法引入某个包下的隐式转换函数,比如import test._。通常建议,仅仅在需要进行隐式转换的地方,比如某个函数或者非法内,用import导入隐式转换函数,这样可以缩小隐式转换函数的作用域,避免不需要的隐式转换。
    
6.4:隐式转换的发生时机:
    a、调用某个函数,但是给函数传入的参数的类型,与函数定义的接受参数类型不匹配。
    b、使用某个类型的对象,调用某个方法,而这个方法并不存在与该类型中。
    c、使用某个类型的对象,调用某个方法,虽然该类型有这个方法,但是给方法传入的参数类型,与方法定义的接受参数的类型不匹配。
6.5:隐式参数:
    所谓的隐式参数,指的是在函数或者方法中,定义一个用implicit修饰的参数,此时Scala会尝试找到一个指定类型的,用implicit修饰的对象,即隐式值,并注入参数。Scala会在两个范围内查找,一种是当前作用域内可见的val或者var定义的隐式变量。一种是隐式参数类型的伴生对象内的隐式值。
    class SignPen {

      def write(context: String) = println(context);
    }
    object Object {

      implicit val signPen = new SignPen;

      def signForExam(name : String)(implicit  signPen : SignPen){
        signPen.write(name + " come to exam in time;")
      }
      def main(args: Array[String]): Unit = {
        signForExam("张三三");
      }
    }

7:Scala之Actor(多线程编程,注意,Spark中使用的分布式多线程框架,是Akka):

  Scala的Actor类似于Java中的多线程编程。但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能的避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提示多线程编程的性能。此外,Scala的Actor的这种模型还可以避免死锁等一系列传统多线程编程的问题。

7.1:Actor的创建,启动,和消息的收发:
    Scala提供了Actor trait来让我们更方便的进行Actor多线程编程,就Actor trait就类似于Java中的thread和Runnable一样,是基础的多线程基类和接口。我们只要重写Actor trait的act方法,即可实现自己的线程执行体,与Java中重写run方法类似。
    此外,使用start()方法启动actor,使用!符号,向actor发送消息。actor内部使用receive和模式匹配接受消息。
    class HelloActor extends Actor{

      def act(): Unit = {
        while(true) {
          receive{
            case name : String => println("hi," + name)
          }
        }
      }
    }
    //定义一个Object来进行测试
    object Object {

      def main(args: Array[String]): Unit = {
        val helloActor = new HelloActor;
        helloActor.start()
      }
    }
7.2:收发case class类型的消息:
    Scala的Actor模型和Java的多线程模型之间,很大的一个区别就是,Scala Actor天然支持线程之间的精确通信。即一个actor可以给其他actor直接发送消息。这个功能是非常强大和方便的。要给一个actor发送消息,需要使用"actor ! 消息"的语法。在Scala中,通常建议使用样例举,即case class来作为消息进行发送。然后在actor接受消息以后,可以使用scala强大的模式匹配功能来进行不同消息的处理。
    case class Login(name : String,passsword : String) {

    }
    case class register(name : String,password : String) {

    }
    class UserManageActor extends Actor{

      def act(): Unit = {
        while (true){
          receive{
            case Login(name,passsword) => println("name : " + name + ",password : " + passsword);
            case register(name,passsword) => println("name : " + name + ",password : " + passsword);
          }
        }
      }
    }
    //定义一个Object来进行测试
    object Object {

      def main(args: Array[String]): Unit = {
        val userManageActor = new UserManageActor;
        userManageActor.start();
        //userManageActor ! Register("张三三","123456");
        //userManageActor ! Login("张三三","123456");
      }
    }

7.3:Actor之间互相收发消息:
    如果两个Actor之间要互相收发消息,那么Scala的建议是,一个actor向另一个actor发送消息时,同时带上自己的引用。其他actor收到自己的消息时,直接通过发送消息的actor的引用,即可以给它回复消息。
    
7.4:同步消息和Future:
    默认情况下,消息都是异步的。但是如果希望发送的消息时同步的,即对方接受后,一定要给自己返回结果,name可以使用!?的方式发送消息。即val reply = actor !? message;如果要异步发送一个消息,但是在后续要获得消息的返回值,那么可以使用Future。即!!语法。val future = actor !! message。val reply = future();
    

待续......