scala 语法深析

时间:2022-07-22
本文章向大家介绍scala 语法深析,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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";

2.也可以不指明(此时必须初始化,才能类型推断)

var yourVar = "Foo";
val yourVal = "Foo";

3.多变量声明

var xmax, ymax = 100;

4.声明元组

var tuple = (40,"Foo")

5.String类型 Scala本身没有String类,其类型实际上是Java String,而Java的String对象的值是不可变的,与java一样,要创建一个可修改的字符串,可以使用StringBuilder类。

val buf = new StringBuilder;
buf += 'a';
buf ++= "bcdef";    //都不会重新创建对象
println( "buf is : " + buf.toString );

6.数组类型

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)

7.集合

// 定义整型 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)

8.迭代器 迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法。

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")
    }
  }
}