scala 語(yǔ)法深析

scala是一種基于JVM的編程語(yǔ)言,spark框架是使用scala語(yǔ)言編寫的,要閱讀源碼就必須掌握scala,雖然spark可以采用java和python進(jìn)行開發(fā),但是最快速的支持方式任然是scala方式的API.

scala的特征

  • java與scala可以實(shí)現(xiàn)混編,因?yàn)槠涠际腔贘VM的
  • 類型推測(cè),scala可以不指定類型
  • 特別接口trait(java中的interfaces與abstract結(jié)合)
  • 模式匹配,match case(類似java switch case)
  • 高階函數(shù)(函數(shù)的參數(shù)是函數(shù),函數(shù)的返回是函數(shù)),可進(jìn)行函數(shù)式編程
  • 并發(fā)和分布式(Actor,類似Java多線程Thread)

scala特有類型

  1. Null :Trait,唯一實(shí)例null,是anyRef的子類
  2. Nothing :Trait,anyRef和anyVal的共同子類
  3. None :Option的兩個(gè)子類有some和None
  4. Unit :無(wú)返回值的函數(shù)類型,和void相對(duì)應(yīng)
  5. Nil :長(zhǎng)度為0 的list
  • Any所有類型的超類,任何實(shí)例都屬于Any類型
  • AnyRef所有引用類型的超類
  • AnyVal所有值類型的超類
  • Nothing所有其他類型的子類

變量的聲明

一般變量用var聲明,常量用val聲明,常量聲明后不能修改

  1. 可以指明變量類型(這種聲明的時(shí)候可以不用初始化)
var myVar : String = "Foo";
val myVal : String = "Foo";
  1. 也可以不指明(此時(shí)必須初始化,才能類型推斷)
var yourVar = "Foo";
val yourVal = "Foo";
  1. 多變量聲明
var xmax, ymax = 100;
  1. 聲明元組
var tuple = (40,"Foo")
  1. String類型
    Scala本身沒(méi)有String類,其類型實(shí)際上是Java String,而Java的String對(duì)象的值是不可變的,與java一樣,要?jiǎng)?chuàng)建一個(gè)可修改的字符串,可以使用StringBuilder類。
val buf = new StringBuilder;
buf += 'a';
buf ++= "bcdef";    //都不會(huì)重新創(chuàng)建對(duì)象
println( "buf is : " + buf.toString );
  1. 數(shù)組類型
var z = Array("Runoob", "Baidu", "Google");
var z:Array[String] = new Array[String](3);
//多維數(shù)組
var myMatrix = ofDim[Int](3,3);
//合并數(shù)組
var myList1 = Array(1, 2, 3);
var myList2 = Array(4, 5, 6);
var myList3 =  concat( myList1, myList2);    //123456;concat函數(shù):import Array._;
//創(chuàng)建區(qū)間數(shù)組:使用range方法,返回一個(gè)數(shù)組Array
var yourList1 = range(10, 20, 2);    //arg3是步長(zhǎng),默認(rèn)為1(不包含20)
  1. 集合
// 定義整型 List
//List的特征是其元素以線性方式存儲(chǔ),集合中可以存放重復(fù)對(duì)象。
val x = List(1,2,3,4)
// 定義 Set
//Set是最簡(jiǎn)單的一種集合。集合中的對(duì)象不按特定的方式排序,并且沒(méi)有重復(fù)對(duì)象。
var x = Set(1,3,5,7)
// 定義 Map
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
// 創(chuàng)建一個(gè)元組(這里包含兩個(gè)不同類型元素)
val x = (10, "Runoob")
// 定義 Option
//表示有可能包含值的容器,也可能不包含值
val x: Option[Int] = Some(5)
  1. 迭代器
    迭代器不是一個(gè)容器,更確切的說(shuō)是逐一訪問(wèn)容器內(nèi)元素的方法。
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())
}

類與對(duì)象

  1. class成為伴生類,class中的屬性都是動(dòng)態(tài)的,scala中的class類默認(rèn)可以傳參數(shù),默認(rèn)的傳參數(shù)就是默認(rèn)的構(gòu)造函數(shù)。class 類屬性自帶getter ,setter方法。使用class時(shí)要new 。
  2. object: 修飾的稱為伴生對(duì)象;定義在object中的屬性(字段、方法)都是靜 態(tài)的,main函數(shù)寫在里面;scala 中的object是單例對(duì)象,可以看成是定義靜態(tài)的方法的類.object不可以傳參數(shù)。使用object時(shí),不用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 的坐標(biāo)為:" + x);
    println("y 的坐標(biāo)為:" + y);
  }
}
//主函數(shù)
object Test {
  def main(args: Array[String]) {
    //創(chuàng)建一個(gè)Point對(duì)象
    var pt = new Point(10, 20);
    pt.move(10, 10);
  }
}

①當(dāng)參數(shù)用==var==修飾那么可以通過(guò)對(duì)象修改其值;當(dāng)參數(shù)用==val==修飾那么無(wú)法通過(guò)對(duì)象來(lái)修改值;當(dāng)參數(shù)沒(méi)有修飾符,那么在外部無(wú)法通過(guò)對(duì)象來(lái)調(diào)用。
②若想增加一個(gè)類的傳入?yún)?shù),則需要在聲明的類中重寫this構(gòu)造函數(shù),這樣就可以在mian函數(shù)中聲明有增加的屬性的對(duì)象,當(dāng)然原來(lái)的對(duì)象也可以聲明。

重寫this函數(shù)
 /*
   *  重寫的構(gòu)造函數(shù),參數(shù)不能有修飾符
   */
  def this (id:Int,name:String,facePower:Double ){
    //首先要調(diào)用父構(gòu)造函數(shù)
    this(id,name)
    fcp = facePower
    
  }
apply方法

使用此方法時(shí),可以在main函數(shù)中不通過(guò)new來(lái)創(chuàng)建一個(gè)對(duì)象,加載創(chuàng)建對(duì)象的這個(gè)類的時(shí)候,會(huì)自動(dòng)調(diào)用apply這個(gè)方法。

object ScalaDemo01 {
  def main(args: Array[String]): Unit = {
    val p = new Person("zs",19)
     val person = Person("wagnwu",10)   //不用使用new來(lái)創(chuàng)建一個(gè)實(shí)例
  }
}

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方法的例子,類對(duì)象會(huì)自動(dòng)調(diào)用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只能重寫另一個(gè)def,val只能重寫另一個(gè)val或者是不帶參數(shù)的def,var只能重寫另一個(gè)抽象的var

循環(huán)控制

to包含最后一個(gè)數(shù),until不包含最后一個(gè)數(shù)

for(x <- 1 to 10)

for(x <- 1 until 10)

相當(dāng)于二重循環(huán)

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

對(duì)集合的循環(huán)遍歷
for( var x <- List )

for循環(huán)當(dāng)作過(guò)濾器

 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;

方法函數(shù)

def functionName ([參數(shù)列表]) : [return type] = {
   function body
   return [expr]
}

如果方法沒(méi)有返回值,可以返回為 Unit,這個(gè)類似于 Java 的 void

**不寫明返回值的類型,程序會(huì)自行判斷,最后一行代碼的執(zhí)行結(jié)果為返回值

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

或者可以簡(jiǎn)寫為一行

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

省去def = {}
表示定義函數(shù)addInt,輸入?yún)?shù)有兩個(gè),分別為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))
偏函數(shù)
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")

//想要調(diào)用log,以上變化的是第二個(gè)參數(shù),可以用偏應(yīng)用函數(shù)處理
val logWithDate = log(date,_:String)    //下劃線相當(dāng)于占位符的作用,手動(dòng)傳入即可
logWithDate("log11")
高階函數(shù)

高階函數(shù):函數(shù)的參數(shù)是函數(shù),或者函數(shù)的返回類型是函數(shù),或者函數(shù)的參數(shù)和函數(shù)的返回類型是函數(shù)的函數(shù)。

    //函數(shù)的參數(shù)是函數(shù)
    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))
    
    //函數(shù)的返回是函數(shù)
    //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))
    
    //函數(shù)的參數(shù)是函數(shù),函數(shù)的返回是函數(shù)
    def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
      f
    } 
    println(hightFun3(f)(100,200))
    println(hightFun3((a,b) =>{a+b})(200,200))
    //以上這句話還可以寫成這樣
    //如果函數(shù)的參數(shù)在方法體中只使用了一次 那么可以寫成_表示
    println(hightFun3(_+_)(200,200))

Trait特性

Trait的概念理解
1》 Scala Trait(特征) 相當(dāng)于 Java 的接口,實(shí)際上它比接口還功能強(qiáng)大。
2》與接口不同的是,它還可以定義屬性和方法的實(shí)現(xiàn)。抽象類和接口的結(jié)合。
3》一般情況下Scala的類可以繼承多個(gè)Trait,從結(jié)果來(lái)看就是實(shí)現(xiàn)了多重繼承。Trait的繼承用exten關(guān)鍵字繼承,多繼承時(shí)多個(gè)Trait之間用with連接。
4》Trait(特征) 定義的方式與類類似,但它使用的關(guān)鍵字是 trait。
5》繼承的多個(gè)trait中如果有同名的方法和屬性,必須要在類中使用“override”重新定義。
6》trait中不可以傳參數(shù)
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 提供了強(qiáng)大的模式匹配機(jī)制,應(yīng)用也非常廣泛,除了匹配值還可以匹配類型,類型的匹配必須要有變量名。
一個(gè)模式匹配包含了一系列備選項(xiàng),每個(gè)都開始于關(guān)鍵字 case。
每個(gè)備選項(xiàng)都包含了一個(gè)模式及一到多個(gè)表達(dá)式。箭頭符號(hào) => 隔開了模式和表達(dá)式。

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())
    }
    
  }
  /**
   * 注意點(diǎn):
   * 1.模式匹配不僅可以匹配值,還可以匹配類型
   * 2.模式匹配中,從上到下順序匹配,如果匹配到對(duì)應(yīng)的類型或值,就不再繼續(xù)往下匹配
   * 3.模式匹配中,都匹配不上時(shí),會(huì)匹配到 case _ ,相當(dāng)于default
   * 4. 模式匹配的時(shí)候,模式范圍小的在最前面
   */
  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")
    }
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容