Scala编程

Scala编程

Scala是什么

  • Scala是一门多范式的编程语言,设计来面向对象和函数式编程的各种特性,Scala运行在java虚拟机上,并兼容现有的Java程序,Scala源代码被编译成字节码,并可以调用现有的Java类库。

第一个Scala程序

  • 程序代码

     

    package com.peng.scala
    
    object Test {
      def main(args: Array[String]) {
        print("Hello World!");
      }
    }
    
  • 执行结果

     

    Hello World!
    

Scala特性

  1. 面向对象
    • Scala是一种纯面向对象的语言,每个值都是对象。对象的数据类型以及行为由类和特质进行描述。类抽象机制的扩展有两种途径:一种是子类继承,另一种是灵活的混入机制。这两种途径能避免多重继承的种种问题。
  2. 函数式编程
    • Scala也是一种函数式语言,其函数也能当成值来使用,Scala提供了轻量级的语法定义匿名函数,支持高阶函数,允许嵌套多层函数,支持柯里化【是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术】,Scala的case class及其内置的模式匹配相当于函数式编程语言中常用的代数类型。更进一步来说,可以使用Scala的模式匹配,编写类似正则表达式的代码处理XML数据。
  3. 静态类型
    • Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。类型系统具体支持以下特性
      1. 泛型类
      2. 协变和逆变
      3. 标注
      4. 类型参数的上下限约束
      5. 把类别和抽象类型作为对象成员
      6. 符合类型
      7. 引用自己时显示指定类型
      8. 视图
      9. 多台方法
  4. 扩展性
  5. Scala的设计秉承一项事实,即在实战中,某个领域特定的应用程序开发往往需要特定于该领域的语言扩展。Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构。
    • 任何方法可用作前缀或后缀操作符
    • 可以根据预期类型自动构造闭包
  6. 并发性
  7. Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息,Actor可以复用线程,因此可以在程序中使用数百万个Actor,而线程只能创建数千个。在2.10之后的版本中,使用Akka作为其默认的Actor实现。

Scala在Windows上的安装

  • 安装步骤
    1. 下载Scala的msi二进制包
    2. 进行安装
    3. 环境变量设置
      • SCALA_HOME=安装Scala的路径
      • Path中;%SCALA_HOME%\bin;%SCALA_HOME%\jre\bin;
      • ClassPath中;%SCALA_HOME%\bin;%SCALA_HOME%\lib\dt.jar;%SCALA_HOME%\lib\tools.jar.;
    4. 测试Scala环境
      • win+r快捷键调出cmd,输入scala

Scala基础语法

  • Scala与Java语言的最大区别就是Scala语句末尾的分号是可选的
  • Scala可以认为是对象的集合,通过调用彼此的方法来实现消息传递
    • 对象:对象有属性和行为
    • 类:类是对象的抽象,而对象是类的具体实例
    • 方法:方法描述的基本的行为,一个类可以包含多个方法
    • 字段:每个对象都有它唯一的实例变量集合,即字段。对象的属性通过给字段赋值来创建。

dos窗口下的Scala编程

脚本形式的Scala编程

Scala的基本语法

  • Scala的基本语法需要注意一下几点
    1. 区分大小写:Scala对于大小写是敏感的
    2. 类名:对于所有的类名的第一个字母要大写
    3. 方法名称:所有的方法名称第一个字母要小写
    4. 程序文件名,程序的文件名应该与对象名称完全匹配,虽然新的版本没有这种要求了,但是还是建议保存这种习惯
    5. 方法开始处理的入口def main(args:Array[String]),这是每一个Scala程序的强制程序入口部分。

Scala标识符

  • Scala可以使用两种形式的标识符,字符数字和符号。
    1. 字符数字使用字母或是下划线开头,后面可以接字母或是数字,符号$在Scala也看最是字母,然而$开头的标识符为保的Scala编译器产生的标识符使用,应用程序应该避免使用$开始的标识符,以免造成冲突。
    2. Scala的命名规则采用和Java的camel命名规则,首字母小写,比如toString()。类名的首字母大写,此外应该避免使用以下划线结尾的标识符以免冲突,符号标识符包含一个或多个符号,如+m:,?等(如:+ ++ ::: < ?>:->)
  • Scala内部实现会使用转义的标识符,比如:->使用$colon$minus$greater来表示这个符号。因此如果你需要在java代码中访问:->方法,你需要使用Scala的内部名称$colon$minus$greater。
  • 混合标识符由数字标识符后面跟一个或多个符号组成,比如unary_+为Scala对+方法的内部实现时的名称。字面量标识符为使用"定义的字符串,比如'x''yield'
  • 你可以在"之间使用任何有效的Scala标识符,Scala将它们解释为一个Scala标识符,一个典型的使用为Thread的yield方法,在Scala中你不能shiyongThread.yield()是因为yield为Scala的关键字,你必须使用Thread.'yield'来使用这个方法

Scala的关键字

  • abstract、case、catch、class、def、do、else、extends、false、final、finally、for、forSome、if、implicit、import、lazy、match、new、null、object、override、package、private、protected、return、sealed、super、this、throw、trait、try、true、type、val、var、while、with、yield、-、:、=、=>、<-、<:、<%、>:、#、@

Scala注释

  • 多行注释

     

    /*
     *多行注释
     *
     */
    
  • 单行注释

     

    //单行注释
    

空行和空格

  • 一行中只有空格或者带有注释,Scala会认为其是空行,会忽略它,标记可以被空格或者注释来分割。

换行符

  • Scala是面向行的语言,语句可以用分号(;)结束或是换行符。Scala程序里,语句末尾的分号通常是可选的如果你愿意可以输入一个,但若一行里仅有一个语句也可不写。另一方面,如果一行里写多个语句那么分号是需要的。列入

     

    println("hello");println("world");
    

Scala包

  • Scala用package关键字定义包【两种方式】
    1. 第一种方法和Java一样

       

      package com.peng
      class HelloWord
      
    2. 第二种方法类似C#

       

      package com.peng{
          class HelloWorld
      }
      

引用

  • Scala使用import关键字引用包
    1. import java.awt.Color //引入Color
    2. import java.awt._ //引入包内所有成员
    3. import java.awt.{Color,Font} //选择器(选择awt包中的Color和Font工具类)
    4. import java.util.{HashMap => JavaHashMap} //重命名成员
    5. import java.util.{HashMap => ,} //引入了util包的所有成员,但是HashMap被隐藏了

数据类型

  • Byte、Short、Int、Long、Float、Double、Char、String、Boolean、Unit【无值,和其他语言中的void等同】、Null、Nothing【Nothing类型在scala的类层级的最低端,他是任何其他类型的子类型】、Any【Any是所有其他类的超类】、AnyRef【AnyRef类是里所有引用类(reference class)的基类】

Scala变量

  • 变量是一种使用方便的占位符,用于引用计算机内存地址,变量创建之后会占用一定的内存空间。基于变量的数据类型,操作系统会进行内存分配并且决定什么将被保留到内存中,因此,通过给变量分配不同的数据类型,你可以在这些变量中存储整数,小数或者字母。
  • 在程序运行过程中值可能发生改变的量叫做变量【在scala中,用var表示】

常量

  • 在程序执行过程中值不会发生变化的量叫做常量【在scala中,用val表示】

变量类型声明

  • var VariableName:DataType [= Initial Value]
    • 例:var aa:String="你好,世界!";
  • 变量声明一定需要初始值,否则会报错
  • 变量类型引用中,不一定要指明数据的类型
    • 例:var aa="你好,世界!";
  • 多个变量的声明
    • 例:var a,b,c=100;

Scala的修饰符

  • Scala的修饰符基本和java一样,分别有private,protected,public
  • 如果没有指定访问修饰符,默认情况下Scala对象的访问级别都是public
  • Scala中的private限定符,比java更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。
  • 在Scala中,对保护(Protected)成员的访问相比java更严格一些,因为它只允许保护成员在定义了该成员的类的子类中被访问,而在Java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问

作用域保护

  • Scala中,访问修饰符可以通过使用限定词强调,格式为:
    • private[x]
    • protected[x]
  • 这里的x代表所属的包、类或单例对象。如果写成private[x],读作“这个成员除了对[...]中的类或[...]中的包中的类及他们的伴生对象可见外,对其他所有的类都是private”
  •  

    package bobsrocckets{
        package navigation{
            private[bobsrockets] class Navigator{
             protected[navigation] def useStarChart(){}
             class LegOfJourney{
                 private[Navigator] val distance = 100
                 }
                private[this] var speed = 200
                }
            }
            package launch{
            import navigation._
            object Vehicle{
            private[launch] val guide = new Navigator
            }
        }
    }
    
    //上述例子中,类Navigator被标记为private[bobsrockets],就是说这个类对包含在bobsrocckets包里的所有的类和对象可见。
    

Scala运算符

  • 算数运算符【+ - * / %】
  • 关系运算符【== != > < >= <=】
  • 逻辑运算符【&& || !】
  • 位运算符【~ & | ^ << >> >>>】
  • 赋值运算符【= += -= *= /= %= <<= >>= &= ^= |=】

运算符的优先级

类别运算符关联性
1()[]左到右
2!~右到左
3*/%左到右
4+-左到右
5>> << >>>左到右
6> >= < <=左到右
7== !=左到右
8&左到右
9^左到右
10左到右
11&&左到右
12短路或左到右
13= += -= *= /= %= >>= <<= &= ^=右到左
14,左到右

Scala中的三大结构

  • 选择结构
    1. if
    2. if...else
    3. if...else if
  • 循环结构

    1. while
    2. do...while【至少执行一次】
    3. for

      •  

        for(var x<- Range){
            println(x);
        }
        
        
        //循环10次 
        for(a <- 1 to 10){
            println(x);
        }
        

Scala方法与函数

  • Scala方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话说在类中定义的函数即是方法
  • Scala中的方法根java的类似,方法是组成类的一部分
  • Scala中的函数则是一个完整的对象,Scala中的函数其实就是继承了Trait的类的对象
  • Scala中使用val语句可以定义函数,def语句定义方法
    •  

      class Test{
          def m(x:Int)=x+3
          val f=(x:Int) => x+3
      }
      
  • 方法声明格式如下

     

    def functionName([参数列表]):[return type]
    //注:如果你不写等号和方法主体,那么方法会被隐式声明为抽象
    
  • 方法定义

     

    def functionName([参数列表]):[returnType]={
        function body
        return [expr]
    }
    
  •  

    package com.peng.scala
    
    object Test {
    
      def main(args: Array[String]) {
        //调用
        print(add(1, 2));
      }
    
      //求和函数
      def add(a: Int, b: Int): Int = {
        var sum: Int = 0;
        sum = a + b;
        return sum;
      };
    
    }
    
  • 如果方法没有返回值,可以返回Unit,这个类似于java的void

Scala闭包

  • 闭包是一个函数,返回值依赖在声明在函数外部的一个或多个变量;闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
  •  

    package com.peng.scala
    
    object Test {
    
      def main(args: Array[String]) {
        print(mutiplier(2));
      }
    
      var factor = 66;
      val mutiplier = (i: Int) => i * factor;
    
    }
    

Scala字符串

  • 在Scala中,字符串的类型实际上是Java String,它本身没有String类,String是一个不可变对象,所以该对象不可以被修改,这就意味着你如果修改字符串就会产生一个新的字符串对象。String是不可变的对象,如果创建一个需要修改的字符串,可以使用String Builder
  • 创建字符串
    1. var s="hello world";
    2. var s:String="hello world";
  • 字符串长度length()方法
  • 字符串连接concat(String)方法或直接使用+号
  • 创建格式化的字符串printf函数

    •  

      package com.peng.scala
      
      object Test {
        def main(args: Array[String]) {
          var s = printf("浮点型变量为 %f, 整型变量为 %d, 字符串为 %s", 200.0, 66, 3);
          println(s)
        }
      }
      
      //执行结果
      浮点型变量为 200.000000, 整型变量为 66, 字符串为 3()
      
  • 插值
    • s

       

      val name = “James”
      println(s “Hello, $name”) //output: Hello, James
      
    • f

       

      val height = 1.9d
      val name = "James"
      println(f"$name%s is $height%2.2f meters tall") //James is 1.90 meters tall
      
    • raw

       

      object Demo {
       def main(args: Array[String]) {
          println(raw"Result = \n a \n b")//Result = \n a \n b
       }
      }
      
  • String方法【同Java中的String方法】

Scala数组

  • Scala语言提供的数组是用来存储固定大小的同类型元素
  • Scala中的数组

     

    var z:Array[String]=new Array[String](2);
    
    //或
    
    var z=new Array[String](2);
    
    z(0)="z0";
    z(1)="z1";
    
  • Scala中的多维数组

     

    package com.peng.scala
    
    object Test {
      def main(args: Array[String]) {
        val arr2 = Array.ofDim[String](2, 2)
        arr2(0)(0) = "aa"
        arr2(1)(0) = "bb"
        for (i <- 0 until arr2.length; j <- 0 until arr2(0).length) {
          println(arr2(i)(j))
        }
      }
    }
    
  • 合并数组Array.concat

     

    package com.peng.scala
    
    object Test {
      def main(args: Array[String]) {
        var s1 = new Array[String](3);
        var s2 = new Array[String](2);
    
        s1(0) = "s11";
        s1(1) = "s12";
        s1(2) = "s13";
    
        s2(0) = "s21";
        s2(1) = "s22";
    
        var result = Array.concat(s1, s2);
    
        for (temp <- result) {
          println(temp);
        }
      }
    }
    
    //执行结果
    s11
    s12
    s13
    s21
    s22
    
  • 创建区间数组range

    • 参数(开始,结束,步长)

       

      package com.peng.scala
      
      object Test {
        def main(args: Array[String]) {
          var r1 = Array.range(1, 100, 3);
          for(temp <- r1){
            print(temp+"\t");
          }
        }
      }
      
  • Scala数组的方法
    1. apply创建
    2. concat合并
    3. copy复制
    4. empty返回长度为0的数组
    5. iterate返回指定长度的数组
    6. fill填充数组
    7. ofDim创建数组
    8. range创建分区数组
    9. tabulate返回指定长度的数组内容【默认从0开始】

Collection

  • List:特征是其元素以线性方式存储,集合可以存放重复对象
    •  

      val l=List(1,2,3);
      
  • Set:Set是最简单的一种集合,集合中的对象不按特定的方式排序,并且没有重复对象
    •  

      val s=Set(1,2,3);
      
  • Map:是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象
    •  

      val m=Map("one"->1,"two"->2);
      
  • 元组:元组是不同类型的值的集合
    •  

      val y=(10,"hello");
      
  • Option表示有可能包含值的容器,也可能不含值
    •  

      val o:Option[Int]=Some(5)
      
  • Iterator:迭代器,迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法

    • Iterator不是一个集合,它是一种用于访问集合的方法
    • Iterator的两个基本方法是next()和hasNext()
    • 调用it.next()会返回迭代器的下一个元素,并且更新迭代器的状态
    • 调用hasNext()用于检测集合中是否还有元素

       

      package com.peng.scala
      
      object Test {
        def main(args: Array[String]) {
          val it = Iterator("a", "b", "c");
          while (it.hasNext) {
            print(it.next() + "\t");
          }
        }
      }
      
      //执行结果
      a   b   c
      
    • 查找最大、最小元素

       

      package com.peng.scala
      
      object Test {
        def main(args: Array[String]) {
          val it = Iterator("a", "w", "c");
          print("最大的元素为:"+it.max);
        }
      }
      
    • Iterator的长度

       

      package com.peng.scala
      
      object Test {
        def main(args: Array[String]) {
          val it1 = Iterator("a", "w", "c");
          val it2 = Iterator("a", "w", "c", "d");
          print("长度:" + it1.length);
          print("长度:" + it2.size);
        }
      }
      
      //执行结果
      长度:3长度:4
      
    • Iterator其他的方法【见Scala的Iterator的API】

Scala的类和对象

  • 类是对象的抽象,而对象是类的实例化,类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
  •  

    package com.peng.scala
    
    class Point(xc: Int, yc: Int) {
    
      var x: Int = xc;
      var y: Int = yc;
    
      def move(dx: Int, dy: Int) {
        x = x + dx;
        y = y + dy;
        print("x的坐标为:" + x + ",y的坐标为:" + y);
      }
    
    }
    
    object PointTest {
      def main(args: Array[String]) {
        val point = new Point(1, 2);
        point.move(3, 4);
      }
    }
    
  • 继承

    1. 重写一个非抽象方法必须使用override关键字
    2. 只有在主构造函数才可以往基类的构造函数里写参数
    3. 在子类中重写超类的抽象方法时,你不需要使用override关键字
    4.  

      package com.peng.scala
      
      class Point(xc: Int, yc: Int) {
      
        var x: Int = xc;
        var y: Int = yc;
      
        def move(dx: Int, dy: Int) {
          x = x + dx;
          y = y + dy;
          print("x的坐标为:" + x + ",y的坐标为:" + y);
        }
      
      }
      
      class Location(val xc: Int, val yc: Int, val zc: Int) extends Point(xc, yc) {
        var z: Int = zc;
      
        def move(dx: Int, dy: Int, dz: Int) {
          x = x + dx;
          y = y + dy;
          z = z + dz;
          print("x的坐标为:" + x + ",y的坐标为:" + y + ",z的坐标为" + z);
        }
      
      }
      
      object PointTest {
        def main(args: Array[String]) {
          val point = new Location(1, 2, 3);
          point.move(3, 4, 5);
        }
      }
      

Scala单例对象

  • 在Scala中,是没有static这个东西的,但是它也为我们提供了单例的实现方法,那就是使用关键字object,Scala中使用单例模式时,除了定义的类之外,还要定义一个同名的object对象,object对象不能带参数。当单例对象与某个类共享同一个名称时,他被称作这个类的伴生对象:companion object.你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class,类和它的伴生对象可以互相访问其私有成员。
  • 单例对象实例【object】

     

    package com.peng.scala
    
    class Poin(val xc: Int, val yc: Int) {
    
      var x: Int = xc;
      var y: Int = yc;
    
      def move(dx: Int, dy: Int) {
        x = x + dx;
        y = y + dy;
      }
    
    }
    
    object Tes {
      def main(args: Array[String]) {
        val poin = new Poin(10, 20);
    
        printPoin
    
        def printPoin {
          poin.move(4,5);
          println("x的坐标:" + poin.x);
          println("y的坐标:" + poin.y);
        }
      }
    }
    
  • 伴生对象与伴生类实例

    • object和class的名称相同,互为【伴生类或伴生对象】,在class中可以直接通过object的名称访问object中的对象

       

      package com.peng.scala
      
      object University {
        private var studentNo = 0
        def newStudentNo = {
          studentNo += 1
          studentNo
        }
      }
      
      class University {
        val id = University.newStudentNo
        private var number = 0
        def aClass(number: Int) { this.number += number }
      }
      

Scala中的Trait【特征】

  • Scala中的Trait相当于Java中的接口,实际上它比接口的功能更加强大。与接口不同的是,它还可以定义属性和方法的实现。
  • 一般情况下Scala的类只能够继承单一父类,但是如果Trait的话就可以继承多个,从结果来看就是实现了多重继承
  • 例子

     

    package com.peng.scala
    
    trait Equal {
      def isEqual(x: Any): Boolean;
      def isNotEual(x: Any): Boolean = !isEqual(x);
    }
    
    class EqualSon(xc: Int, yc: Int) extends Equal {
      var x: Int = xc;
      var y: Int = yc;
      def isEqual(obj: Any) = (obj.isInstanceOf[EqualSon]) && (obj.asInstanceOf[EqualSon].x == x);
    }
    
    object TestEual {
      def main(args: Array[String]) {
        val es23 = new EqualSon(2, 3);
        val es24 = new EqualSon(2, 4);
        val es33 = new EqualSon(3, 3);
        println("(2,3)与(2,4)的比较结果为:" + es23.isEqual(es24));
        println("(2,3)与(3,3)的比较结果为:" + es23.isEqual(es33));
      }
    }
    
    //执行结果【这里主要是比较x的值是否相等】
    (2,3)与(2,4)的比较结果为:true
    (2,3)与(3,3)的比较结果为:false
    

特征构造顺序

  • 特征也可以有构造器,由字段的初始化和其他特征体中的语句构成,这些语句在任何混入该特征的对象在构造时都会被执行。
  • 构造器的执行顺序
    1. 调用超类的构造器
    2. 特征构造器在超类构造器之后、类构造器之前执行
    3. 特征由左到右被构造
    4. 每个特征中,父特征先被构造【如果多个特征共有一个特征,父特征不会被重复构造】
    5. 所有特征被构造完毕,子类被构造
  • 构造器的顺序是类的线性化的反向,线性化是描述某个类型的所有超类型的一种技术规格

Scala的模式匹配

  • 一个模式匹配包含了一系列备选项,每个都开始于关键字case。每个备选项都包含了一个模式及一到多个表达式。箭头符号=>隔开了模式和表达式
  •  

    package com.peng.scala
    
    object ModelCatch {
      def main(args: Array[String]) {
        println(matchTest(0));
        println(matchTest(1));
        println(matchTest(1111));
      }
    
      def matchTest(x: Int): String = x match {
        case 0 => "匹配到0"
        case 1 => "匹配到1"
        case _ => "匹配到非0,1"
      }
    
    }
    
    //执行结果
    匹配到0
    匹配到1
    匹配到非0,1
    
  • 使用样例类

    • 使用了case关键字的类定义就是样例类,样例类是特殊的类,经过优化以用于模式匹配

       

      package com.peng.scala
      
      object Yll {
        def main(args: Array[String]) {
          val p1 = new PP("张三", 12);
          val p2 = new PP("李四", 13);
      
          for (person <- List(p1, p2)) {
            print("开始匹配:")
            person match {
              case PP("张三", 12) => print("【匹配到了张三】")
              case PP("李四", 13) => print("【匹配到了李四】")
            }
            print(",结束一次匹配\n")
          }
        }
      
        case class PP(name: String, age: Int);
      }
      
      //执行结果
      开始匹配:【匹配到了张三】,结束一次匹配
      开始匹配:【匹配到了李四】,结束一次匹配
      

Scala的正则表达式

  • Scala中通过scala.util.matching包的Regex类来支持正则表达式

    •  

      package com.peng.scala
      
      import scala.util.matching.Regex;
      
      object Regextest {
        def main(args: Array[String]) {
          val pattern = new Regex("(S|s)cala\\d+") // 首字母可以是大写 S 或小写 s
          val str = "Scala2 Scalaa is scalable and cool"
          println((pattern findAllIn str).mkString(",")) // 使用逗号 , 连接返回结果
        }
      }
      
      //结果
      Scala2
      

Scala异常处理

  • 抛出异常
    • Scala中的抛出异常的方法和Java一样,使用throw方法,例如

       

      throw new IllegalArgumentException
      
  • 捕获异常

    • 在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后,如果抛出的异常不在catch中,该异常则无法处理,会升级到被调用者处
    • 需要注意的是:catch语法和其他语言不太一致,借用了模式匹配的思想来做异常的匹配
    • 例如

       

      package com.peng.scala
      
      import java.io.FileReader
      import java.io.FileNotFoundException
      import java.io.IOException
      
      object ExceptionTest {
        def main(args: Array[String]) {
          try {
            val f = new FileReader("test.txt");
          } catch {
            case ex: FileNotFoundException => {
              print("FileNotFoundException!");
            }
            case ex: IOException => {
              println("IO Exception!")
            }
            case ex: Exception => {
              println("Exception!")
            }
          } finally {
            print("\nfinal...");
          }
        }
      }
      
      
      //执行结果
      FileNotFoundException!
      final...
      
  • finally语句
    • 不管是正常处理还是异常发生都正常执行

Scala提取器

  • 提取器是从传递给它的对象中提取出构造该对象的参数。Scala标准库包含了一些预定义的提取器,,Scala提取器是一个带有unapply方法的对象,unapply方法算是apply方法的相反的操作:unapply接受一个对象,然后从对象中提取值,提取的值通常是用来构造该对象的值。
  •  

    package com.peng.scala
    
    object UnapplyTest {
    
      def main(args: Array[String]) {
        println("Apply 方法 : " + apply("Zara", "gmail.com"));
        println("Unapply 方法 : " + unapply("Zara@gmail.com"));
        println("Unapply 方法 : " + unapply("Zara Ali"));
    
      }
    
      //注入方法(可选)
      def apply(user: String, domain: String) = {
        user + "@" + domain;
      }
    
      //提取方法(必选)
      def unapply(str: String): Option[(String, String)] = {
        var parts = str split "@"
    
        if (parts.length == 2) {
          Some(parts(0), parts(1))
        } else {
          None
        }
    
      }
    
    }
    
    //执行结果
    Apply 方法 : Zara@gmail.com
    Unapply 方法 : Some((Zara,gmail.com))
    Unapply 方法 : None
    
  • unapply方法算是apply方法的方法的反向操作,unapply接受一个对象,然后从对象中提取值,提取的值通常是用来构造该对象的值。
    • unapply("Zara@gmail.com")相当于Some("Zara","gmail.com")
    • unapply("Zara Ali")相当于None
  • 提取器使用模式匹配

    • 我们在实例化一个类时,可以带上0或多个参数,编译器在实例化的时候会调用apply方法,我们可以在类和对象中部定义apply方法,就想之前提过的unapply方法,当我们在提取器中使用match语句时,unapply将自动执行
    •  

      package com.peng.scala
      
      object CaseUnapplyTest {
        def main(args: Array[String]) {
          val x = CaseUnapplyTest(5);
      
          println(x);
      
          x match {
            case CaseUnapplyTest(num) => print(x + "是" + num + "的两倍")
            //unapply 被调用
            case _                    => println("无法计算")
          }
      
        }
      
        def apply(x: Int) = { x * 2 };
        def unapply(z: Int): Option[Int] = {
          if (z % 2 == 0) {
            Some(z / 2);
          } else {
            None
          }
        }
      }
      
  • apply方法有点类似java中的构造函数,接受构造参数变成一个对象;unapply方法刚好相反,它是接受一个对象,从对象中提取值。

Scala中I/O操作

  • Scala中进行文件写操作,直接用的是java中的I/O类
  • 例,文件的写入操作

     

    package com.peng.scala
    
    import java.io.PrintWriter
    import java.io.File
    
    object IoTest {
      def main(args: Array[String]) {
        val writer = new PrintWriter(new File("io_test.txt"));
        writer.write("hello world!");
        writer.close();
      }
    }
    
  • 执行结果

  • 从屏幕上读取用户输入

    •  

      package com.peng.scala
      
      import scala.io.StdIn
      
      object StdIntest {
        def main(args: Array[String]) {
          println("下面可以进行输入:");
          val line = StdIn.readLine();
          println("您输入的数据是:" + line);
        }
      }
      
      //执行结果
      下面可以进行输入:
      hello world!
      您输入的数据是:hello world!
      
  • 从文件中读取数据

    • 从文件中读取数据非常简单,我们可以使用Scala的Source类及伴生对象来读取文件
    •  

      package com.peng.scala
      
      import scala.io.Source
      
      object FileReadTest {
        def main(args: Array[String]) {
          println("文件的内容为:");
          Source.fromFile("io_test.txt").foreach { print }
        }
      }
      
      //执行结果
      文件的内容为:
      hello world!
      

隐性类

  • 当类在范围内时,隐式类允许与类的主构造函数进行隐式通话。隐式类是一个标有‘impicit’关键字的类,此功能在Scala2.10中引入。
  • 语法(以下是隐式类的语法,这里,隐式类始终位于对象范围内,所有方法定义都被允许 ,因为隐式类不能是顶级类)

     

    object <object name>{
        implicit class <class name>(<Variable>:Data type){
            def <method>():Unit=
        }
    }
    
  •  

    object Run {
    
      //函数执行入口
      def main(args: Array[String]): Unit = {
        4 times print("hi");
      }
    
      //隐性类
      implicit class IntTimes(x: Int) {
        def times[A](f: => A): Unit = {
          def loop(current: Int): Unit =
    
            if (current > 0) {
              f
              loop(current - 1)
            }
    
          loop(x)
        }
      }
    
    }
    
    //执行结果
    hihihihi
    
  • 注:
    1. 隐式类必须放在class、object或trait内【不能在顶层】
    2. 隐式类在其构造函数中只能使用一个非默认参数
    3. 隐式类作用域中不可以具有与隐式类相同名称的的任何方法,成员或对象。

Scala函数

  • 按名称调用的函数

    • 通常函数的参数是按值参数,在参数传递给函数之前确定,但是,如果需要编写一个函数来接受一个表达式作为参数,我们不希望在函数调用之前进行评估怎么办,这种情况下,Scala中可以使用名称参数
    •  

      object Test_Name_Method {
        def main(args: Array[String]): Unit = {
          delayed(time());
        }
      
        def time() = {
          println("time~~")
          System.nanoTime
        }
      
        def delayed(t: Long) = {
          println("delayed~~")
          println("Param: " + t)
        }
      
      }
      
  • 命名参数的函数

    • 在正常的函数调用中,调用的参数按照被调用函数定义的参数顺序逐个匹配,命名参数允许您以不同顺序将参数传递给函数,语法只是每个参数前面都有一个参数名称和一个等号
    •  

      object Test_Params_Method {
        def main(args: Array[String]): Unit = {
          printInt(b = 666, a = 222);
        }
      
        def printInt(a: Int, b: Int): Unit = {
          println("a的值为:" + a);
          println("b的值为:" + b);
        }
      }
      
      //执行结果
      a的值为:222
      b的值为:666            
      
  • 可变参数的函数

    •  

      object More_Params_Method {
        def main(args: Array[String]): Unit = {
          printString("a", "b", "c", "d", "e");
        }
      
        def printString(args: String*) = {
          var i: Int = 1;
          for (arg <- args) {
            println("第" + i + "个参数:" + arg)
            i+=1;
          }
        }
      } 
      
      //执行结果
      第1个参数:a
      第2个参数:b
      第3个参数:c
      第4个参数:d
      第5个参数:e
      
  • 递归函数

    • 递归在纯功能编程中起着重要作用,Scala支持递归函数,递归表示一个函数可以重复调用起自身
    •  

      object DG_Method {
        def main(args: Array[String]): Unit = {
          print("4的阶乘"+factoril(4));
        }
      
        def factoril(n: BigInt): BigInt = {
          if (n <= 1) {
            1;
          } else {
            n * factoril(n - 1);
          }
        }
      
      }
      
      //执行结果
      24
      
  • 默认参数值函数

    • 调用函数时不用写参数
    •  

      object DefaultMethod {
        def main(args: Array[String]): Unit = {
          println(addInt());
        }
      
        def addInt(a: Int = 1, b: Int = 2): Int = {
          var sum: Int = 0;
          sum = a + b;
          return sum;
        }
      }
      
      //执行结果
      3
      
  • 高阶函数

    • Scala允许定义高阶函数,它是将其他函数作为参数或结果是函数的函数
    •  

      object GJ_Method {
        def main(args: Array[String]): Unit = {
          print(apply(layout, 10))
        }
      
        def apply(f: Int => String, v: Int) = f(v)
      
        def layout[A](x: A) = "[" + x.toString() + "]"
      
      }
      
      //结果
      [10]
      
    • 解释:apply函数接受另一个函数f和值v,并将f应用于v
    • 执行过程
  • 嵌套函数

    • Scala允许您来自定义函数内部的函数,而在其他函数中定义的函数成为局部函数,这是一个阶乘计算器的实现,我们使用传统的技术来调用第二个嵌套方法来完成工作
    •  

      object QT_Method {
        def main(args: Array[String]): Unit = {
          print(factorial(4));
        }
      
        def factorial(i: Int): Int = {
          def fact(i: Int, accumulator: Int): Int = {
            if (i <= 1) {
              accumulator
            } else {
              fact(i - 1, i * accumulator);
            }
          }
      
          fact(i, 1);
        }
      }
      
      //执行结果
      24
      
  • 匿名函数

    • Scala提供了一个相对轻量级的语法来定义匿名函数,源代码中的匿名函数成为函数文字,在运行时,函数文字被实例化为称为函数值的对象。
    • Scala支持一级函数,函数可以用函数文字语法表达,及(x:Int)=>x+1,该函数可以由一个叫做函数值的对象来表示
    •  

      object NN_Method {
        def main(args: Array[String]): Unit = {
          var inc = (x: Int) => x + 2;
          print(inc(6));
        }
      }   
      
      //执行结果
      8
      
  • 部分应用函数

    • 当在调用一个函数时,把这个函数应用到参数中,如果您传递所有的预期的参数,则表示您已经完全应用它。如果只传递几个参数,并不是全部参数,name将返回部分应用的函数。这样就可以方便的绑定一些参数,其余的参数可稍后填写补上。
    •  

      object BFYY_Method {
        def main(args: Array[String]): Unit = {
          val date = new Date;
          log(date, "message1");
      
          Thread.sleep(1000);
          log(date, "message2");
      
          Thread.sleep(1000);
          log(date, "message3");
      
          val logWithDateBound = log(date, _: String);
      
          logWithDateBound("m1");
      
          Thread.sleep(1000);
          logWithDateBound("m2");
      
          Thread.sleep(1000);
          logWithDateBound("m3");
        }
      
        def log(date: Date, message: String) = {
          println(date + "....." + message);
        }
      
      }
      
      //结果
      Thu Nov 15 17:10:20 CST 2018.....message1
      Thu Nov 15 17:10:20 CST 2018.....message2
      Thu Nov 15 17:10:20 CST 2018.....message3
      Thu Nov 15 17:10:20 CST 2018.....m1
      Thu Nov 15 17:10:20 CST 2018.....m2
      Thu Nov 15 17:10:20 CST 2018.....m3
      
    • 解释
      • 这里log方法有两个参数,如果想要多次调用该方法,具有相同的日期值和不同的消息值,可以直接使用第一种方案【每次调用log函数都传入两个参数】;也可以升级一下调用的方式【将log调用写到变量中,日期值先进行固定,然后只关注消息的值即可】;
  • 柯里化函数

    • 柯里化(Currying)函数是一个带有多个参数,并引入到一个函数链中的函数,每个函数都使用一个参数
    •  

      object KLH_Method {
        def main(args: Array[String]): Unit = {
          print(strcat("hello ")("world!"));
        }
      
        def strcat(s1: String)(s2: String) = {
          s1 + s2
        }
      }
      
      //执行结果
      hello world!
      
  • Scala闭包

    • 闭包是一个函数,它的返回值取决于在此函数之外的声明的一个或多个变量的值
    •  

      object BB_Method {
        def main(args: Array[String]): Unit = {
          println("multiplier(1) value = " + multiplier(1));
          println("multiplier(2) value = " + multiplier(2));
        }
      
        var factor = 66;
        val multiplier = (i: Int) => i * factor;
      
      }
      
      //执行结果
      multiplier(1) value = 66
      multiplier(2) value = 132
      

Scala多线程

  • 与Java类似
    • Thread

       

      class ThreadExample extends Thread{  
          override def run(){  
          println("Thread is running?");  
          }  
      }  
      object Demo{  
          def main(args:Array[String]){  
              var t = new ThreadExample()  
              t.start()  
          }  
      }
      
    • Runnable

       

      class ThreadExample extends Runnable{  
          override def run(){  
              println("Thread is running...")  
          }  
      }  
      object Demo{  
          def main(args:Array[String]){  
              var e = new ThreadExample()  
              var t = new Thread(e)  
              t.start()  
          }  
      }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值