scala 语法深析

作者: Tim在路上 | 来源:发表于2019-02-17 16:02 被阅读5次

    scala是一种基于JVM的编程语言,spark框架是使用scala语言编写的,要阅读源码就必须掌握scala,虽然spark可以采用java和python进行开发,但是最快速的支持方式任然是scala方式的API.

    scala的特征

    • java与scala可以实现混编,因为其都是基于JVM的
    • 类型推测,scala可以不指定类型
    • 特别接口trait(java中的interfaces与abstract结合)
    • 模式匹配,match case(类似java switch case)
    • 高阶函数(函数的参数是函数,函数的返回是函数),可进行函数式编程
    • 并发和分布式(Actor,类似Java多线程Thread)

    scala特有类型

    1. Null :Trait,唯一实例null,是anyRef的子类
    2. Nothing :Trait,anyRef和anyVal的共同子类
    3. None :Option的两个子类有some和None
    4. Unit :无返回值的函数类型,和void相对应
    5. Nil :长度为0 的list
    • Any所有类型的超类,任何实例都属于Any类型
    • AnyRef所有引用类型的超类
    • AnyVal所有值类型的超类
    • Nothing所有其他类型的子类

    变量的声明

    一般变量用var声明,常量用val声明,常量声明后不能修改

    1. 可以指明变量类型(这种声明的时候可以不用初始化)
    var myVar : String = "Foo";
    val myVal : String = "Foo";
    
    1. 也可以不指明(此时必须初始化,才能类型推断)
    var yourVar = "Foo";
    val yourVal = "Foo";
    
    1. 多变量声明
    var xmax, ymax = 100;
    
    1. 声明元组
    var tuple = (40,"Foo")
    
    1. String类型
      Scala本身没有String类,其类型实际上是Java String,而Java的String对象的值是不可变的,与java一样,要创建一个可修改的字符串,可以使用StringBuilder类。
    val buf = new StringBuilder;
    buf += 'a';
    buf ++= "bcdef";    //都不会重新创建对象
    println( "buf is : " + buf.toString );
    
    1. 数组类型
    var z = Array("Runoob", "Baidu", "Google");
    var z:Array[String] = new Array[String](3);
    //多维数组
    var myMatrix = ofDim[Int](3,3);
    //合并数组
    var myList1 = Array(1, 2, 3);
    var myList2 = Array(4, 5, 6);
    var myList3 =  concat( myList1, myList2);    //123456;concat函数:import Array._;
    //创建区间数组:使用range方法,返回一个数组Array
    var yourList1 = range(10, 20, 2);    //arg3是步长,默认为1(不包含20)
    
    1. 集合
    // 定义整型 List
    //List的特征是其元素以线性方式存储,集合中可以存放重复对象。
    val x = List(1,2,3,4)
    // 定义 Set
    //Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。
    var x = Set(1,3,5,7)
    // 定义 Map
    val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
    // 创建一个元组(这里包含两个不同类型元素)
    val x = (10, "Runoob")
    // 定义 Option
    //表示有可能包含值的容器,也可能不包含值
    val x: Option[Int] = Some(5)
    
    1. 迭代器
      迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法。
    var ita = Iterator(20,40,2,50,69, 90);
    println("最小:" + ita.min);
    println(itb.size + ":" + itb.length);
    println(itb.size + ":" + itb.size);
    while (it.hasNext){
        println(it.next())
    }
    

    类与对象

    1. class成为伴生类,class中的属性都是动态的,scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。class 类属性自带getter ,setter方法。使用class时要new 。
    2. object: 修饰的称为伴生对象;定义在object中的属性(字段、方法)都是静 态的,main函数写在里面;scala 中的object是单例对象,可以看成是定义静态的方法的类.object不可以传参数。使用object时,不用new.
    //Point类文件
    class Point(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;
        println("x 的坐标为:" + x);
        println("y 的坐标为:" + y);
      }
    }
    //主函数
    object Test {
      def main(args: Array[String]) {
        //创建一个Point对象
        var pt = new Point(10, 20);
        pt.move(10, 10);
      }
    }
    

    ①当参数用==var==修饰那么可以通过对象修改其值;当参数用==val==修饰那么无法通过对象来修改值;当参数没有修饰符,那么在外部无法通过对象来调用。
    ②若想增加一个类的传入参数,则需要在声明的类中重写this构造函数,这样就可以在mian函数中声明有增加的属性的对象,当然原来的对象也可以声明。

    重写this函数
     /*
       *  重写的构造函数,参数不能有修饰符
       */
      def this (id:Int,name:String,facePower:Double ){
        //首先要调用父构造函数
        this(id,name)
        fcp = facePower
        
      }
    
    apply方法

    使用此方法时,可以在main函数中不通过new来创建一个对象,加载创建对象的这个类的时候,会自动调用apply这个方法。

    object ScalaDemo01 {
      def main(args: Array[String]): Unit = {
        val p = new Person("zs",19)
         val person = Person("wagnwu",10)   //不用使用new来创建一个实例
      }
    }
    
    class Person(xname :String , xage :Int){
      val name = "zs"
      val age = xage
      var gender = "m"
      def this(name:String,age:Int,g:String){
        this(name,age)
        gender = g
      }
    }
    
    object Person{
      def apply(name:String,age:Int)={
        new Person(name,age)  
      }
    }
    

    上面是使用apply方法的例子,类对象会自动调用apply方法。

    继承

    class SubClassName extends SuperClassName(){  
        /* Write your code  
         *  methods and fields etc. 
         */  
     }
    
    override修饰可以继承 父类final修饰的字段和方法
    class Persion(val name: String){
        override def toString = getClass.getName()+ "[name="+name+"]"
      }
    
    
      class SecretAgent (codename: String) extends Persion(codename){
        override val name = "secret"   //重写 name
        override val toString ="secret" //重写 toString
      }
    
      val p = new SecretAgent("hello")
      println(p.name)
      println(p.toString)
    
    注意:def只能重写另一个def,val只能重写另一个val或者是不带参数的def,var只能重写另一个抽象的var

    循环控制

    to包含最后一个数,until不包含最后一个数

    for(x <- 1 to 10)

    for(x <- 1 until 10)

    相当于二重循环

    for( a <- 1 to 3; b <- 1 to 3){

    对集合的循环遍历
    for( var x <- List )

    for循环当作过滤器

     for(a <- numList
                if a % 2 == 0; if a < 5) {
                    println(a + "");
       }
    
     var retList = for{ a <- numList
                if a % 2 == 0; if a < 5 } yield a;
    
    

    方法函数

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

    如果方法没有返回值,可以返回为 Unit,这个类似于 Java 的 void

    **不写明返回值的类型,程序会自行判断,最后一行代码的执行结果为返回值

    def addInt(a:Int,b:Int) = {
        a + b
    }
    

    或者可以简写为一行

    def addInt(a:Int,b:Int) = x + y
    

    省去def = {}
    表示定义函数addInt,输入参数有两个,分别为x,y,且均为Int类型,返回值为两者的和,类型为Int。

    val addInt = (x:Int,y:Int) =>x + y
    
    递归模型
     def fun2(num :Int) :Int= {  //必须写返回值类型
          if(num ==1)
            num
          else 
            num * fun2(num-1)
        }
        print(fun2(5))
    
    偏函数
    def log(date :Date, s :String)= {
      println("date is "+ date +",log is "+ s)
    }
    
    val date = new Date()
    log(date ,"log1")
    log(date ,"log2")
    log(date ,"log3")
    
    //想要调用log,以上变化的是第二个参数,可以用偏应用函数处理
    val logWithDate = log(date,_:String)    //下划线相当于占位符的作用,手动传入即可
    logWithDate("log11")
    
    高阶函数

    高阶函数:函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。

        //函数的参数是函数
        def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {
          f(a,100)
        }
        def f(v1 :Int,v2: Int):Int  = {
          v1+v2
        }
        
        println(hightFun(f, 1))
        
        //函数的返回是函数
        //1,2,3,4相加
        def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
          def f2 (v1: Int,v2:Int) :Int = {
            v1+v2+a+b
          }
          f2
        }
        println(hightFun2(1,2)(3,4))
        
        //函数的参数是函数,函数的返回是函数
        def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
          f
        } 
        println(hightFun3(f)(100,200))
        println(hightFun3((a,b) =>{a+b})(200,200))
        //以上这句话还可以写成这样
        //如果函数的参数在方法体中只使用了一次 那么可以写成_表示
        println(hightFun3(_+_)(200,200))
    

    Trait特性

    Trait的概念理解
    1》 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
    2》与接口不同的是,它还可以定义属性和方法的实现。抽象类和接口的结合。
    3》一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait的继承用exten关键字继承,多继承时多个Trait之间用with连接。
    4》Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
    5》继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
    6》trait中不可以传参数
    
    trait Read {
      val readType = "Read"
      val gender = "m"
      def read(name:String){
        println(name+" is reading")
      }
    }
    
    trait Listen {
      val listenType = "Listen"
      val gender = "m"
      def listen(name:String){
        println(name + " is listenning")
      }
    }
    
    class Person() extends Read with Listen{
      override val gender = "f"
    }
    
    object test {
      def main(args: Array[String]): Unit = {
        val person = new Person()
        person.read("zhangsan")
        person.listen("lisi")
        println(person.listenType)
        println(person.readType)
        println(person.gender)
        
      }
    }
    

    模式匹配

    Java中的模式匹配为 switch case ;
    Scala 提供了强大的模式匹配机制,应用也非常广泛,除了匹配值还可以匹配类型,类型的匹配必须要有变量名。
    一个模式匹配包含了一系列备选项,每个都开始于关键字 case。
    每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。

    object Lesson_Match {
      def main(args: Array[String]): Unit = {
        val tuple = Tuple6(1,2,3f,4,"abc",55d)
        val tupleIterator = tuple.productIterator
        while(tupleIterator.hasNext){
          matchTest(tupleIterator.next())
        }
        
      }
      /**
       * 注意点:
       * 1.模式匹配不仅可以匹配值,还可以匹配类型
       * 2.模式匹配中,从上到下顺序匹配,如果匹配到对应的类型或值,就不再继续往下匹配
       * 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default
       * 4. 模式匹配的时候,模式范围小的在最前面
       */
      def matchTest(x:Any) ={
        x match {
          case x:Int=> println("type is Int")    //类型匹配,必须要有变量名
          case 1 => println("result is 1")
          case 2 => println("result is 2")
          case 3=> println("result is 3")
          case 4 => println("result is 4")
          case x:String => println("type is String")
    //      case x :Double => println("type is Double")
          case _ => println("no match")
        }
      }
    }
    

    相关文章

      网友评论

        本文标题:scala 语法深析

        本文链接:https://www.haomeiwen.com/subject/jtigeqtx.html