<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    學好Spark必須要掌握的Scala技術點

    VSole2022-07-31 10:05:32

    前言

    Scala是以JVM為運行環境的面向對象的函數式編程語言,它可以直接訪問Java類庫并且與Java框架進行交互操作。

    正如之前所介紹,Spark是用Scala語言編寫的,Kafka server端也是,那么深入學習Scala對掌握Spark、Kafka是必備掌握技能。

    本篇文章主要介紹,在學習、編寫Spark程序時,至少要掌握的Scala語法,多以示例說明。建議在用Scala編寫相關功能實現時,邊學習、邊應用、邊摸索以加深對Scala的理解和應用。

    1. 變量、表達式、循環、Option、方法和函數

    1.1 聲明變量

    def main(args: Array[String]): Unit = {
        //使用val定義的變量值是不可變的,相當于java里用final修飾的變量
        val i = 1
        //使用var定義的變量是可變的,在Scala中鼓勵使用val
        var s = "hello"
        //Scala編譯器會自動推斷變量的類型,必要的時候可以指定類型
        //變量名在前,類型在后
        val str: String = "hello"
    }
    

    1.2 表達式

    1.2.1 條件表達式

    def main(args: Array[String]): Unit = {
        val x = 1
        
        // 判斷x是否大于0,將最終結果賦給y,打印y
        // 二者等效, Scala語言強調代碼簡潔
        //    var y = if(x > 0) {x} else {-1}
        //    val y = if(x > 0) x else -1
        //   支持混合類型表達式,返回值類型是Any
        //    var y = if(x > 0) x else "no"
        // 如果缺失else,相當于if (x > 0) 1 else ()
        //    scala表達式中有一個Unit類,寫作(),相當于java中void
        //    val y = if(x > 0) 1
        //    if和else if
        val f = if (x < 0) 0 else if (x >= 1) 1 else -1
        println(y)
    }
    

    1.2.2 塊表達式

    def main(args: Array[String]): Unit = {
        val x = 0
        
         //  scala中{}可包含一系列表達式,塊中運行最終結果為塊的值
        val result = {
          if(x < 0)  -1  else if(x >= 1) 1  else "error"
        }
        println(result)
    }
    

    1.3 循環

    Scala里面while循環和Java中的while循環使用方式類似,這里主要以for循環為例:

    def main(args: Array[String]): Unit = {
        // 表達式1 to 10返回一個Range區間,每次循環將區間中的一個值賦給i
        for (i <- 1 to 3) {
          println(i)
        }
        //i代表數組中的每個元素
        val arr = Array("a", 1, "c")
        for (i <- arr) {
          println(i)
        }
        
        //高級for循環
        //每個生成器都可以帶一個條件,注意:if前面沒有分號
        //相當于雙層for循環,i每獲得一個值對1to3進行全部遍歷并賦值給j然后進行條件判斷
        for (i <- 1 to 3; j <- 1 to 3 if (i != j)) {
          println(i + j)
        }
        //for推導式:如果for的循環體以yield開頭,則該循環會構建一個集合
        //    每次迭代生成集合中的一個元素 集合類型為Vector
        var v = for (i <- 1 to 3) yield i * i
        println(v)
        //遍歷一個數組,to:包頭包尾;until:包頭不包尾
        for (i <- arr.length - 1) {
          println(arr(i))
        }
        for(i <- 0 until arr.length) {
          println(arr(i))
        }
    }
    

    1.4 Option類型

    在Scala中Option類型樣例類用來表示可能存在或也可能不存在的值(Option的子類有Some和None)。Some包裝了某個值,None表示沒有值:

    def main(args: Array[String]): Unit = {
        val map = Map("a"->1,"b"->2)
    //根據key獲取value匹配match中的邏輯有值返回Some類型(已封裝數據),無值返回None
        val v = map.get("b") match {
          case Some(i) => i
          case None => 0
        }
        println(v)
        //更好的方式
        val value = map.getOrElse("c",0)
        println(value)
      }
    

    1.5 方法和函數

    Scala中的+、-、*、/、%等操作符的作用與Java一樣,位操作符&、|、^、>>、<<也一樣。但在Scala中:這些操作符實際上是方法。例如:a + b是a.+(b)方法調用的簡寫:a 方法 b可以寫成 a.方法(b)。

    方法的返回值類型可以不寫,編譯器可以自動推斷出來,但是對于遞歸函數,必須指定返回類型。

    def str = "a" 成立,定義一個字符串

    在函數式編程語言中,函數可以像任何其他數據類型一樣被傳遞和操作:

    偏函數:

    //偏函數,它是PartialFunction[-A,+B]的一個實例,A代表參數類型,B代表返回值類型,常用作模式匹配(后文闡述)。
    def func1: PartialFunction[String, Int] = {
        case "one" => 1
        case "two" => 2
        case _ => -1
      }
      def func2(num: String): Int = num match {
        case "one" => 1
        case "two" => 2
        case _ => -1
      }
      def main(args: Array[String]) {
        println(func1("one"))
        println(func2("three"))
    }
    

    2. 數組、映射、元組、集合

    2.1 數組

    import scala.collection.mutable.ArrayBuffer
    //scala導包比如導入scala.collection.mutable下所有的類:scala.collection.mutable._
    object ArrayDemo {
      def main(args: Array[String]): Unit = {
        println("======定長數組======")
        // 初始化一個長度為8的定長數組,所有元素初始化值為0
        var arr1 = new Array[Int](8)
        // 底層調用的apply方法
        var arr2 = Array[Int](8)
        
        //toBuffer會將數組轉換成數組緩沖
        println(arr1.toBuffer) // ArrayBuffer(0, 0, 0, 0, 0, 0, 0, 0)
        println(arr1(2)) // 使用()來訪問元素
        
        println("=======變長數組(數組緩沖)======")
        val varr = ArrayBuffer[Int]()
        //向數組緩沖尾部追加一個或多個元素(+=)
        varr += 1
        varr += (2, 3)
        //追加一個數組用 ++=
        varr ++= Array(4, 5)
        varr ++= ArrayBuffer(6, 7)
        //指定位置插入元素-1和3;參數1:指定位置索引,參數2:插入的元素可以是多個
    //    def insert(n: Int, elems: A*) { insertAll(n, elems) }
        varr.insert(0,-1,3)
        
        varr.remove(0) //刪除指定索引處的元素
        //從指定索引處開始刪除,刪除多個元素;參1:指定索引,參2:刪除個數
        varr.remove(0,2)
        
        // 從0索引開始刪除n個元素
        //  varr.trimStart(2)
        //從最后一個元素開始刪除,刪除指定個數的元素(length-n max 0)
        varr.trimEnd(2)
        )
        
        //reduce ==>非并行化集合調用reduceLeft
        //(((1+8)+3)+5)...
        println(varr.reduce((x,y)=> x+y))
        println(varr.reduce(_+_))
        println(varr.reduce(_-_))
    Array("one","two","three").max //two,字符串比較大小,按照字母表順序
    Array("one","two","three").mkString("-")//以"-"作為數組中元素間的分隔符one-two-three
    Array("one","two","three").mkString("1","-","2")//1one-two-three2
        
        //參1:arr元素的數組個數,參2:arr中每個數組中元素個數
       val arr = Array.ofDim[Int](2, 3)
        arr.head arr.last //數組的第一個和最后一個元素
      }
    }
    

    yield關鍵字將原始的數組進行轉換會產生一個新的數組,原始的數組不變

    def main(args: Array[String]) {
        //定義一個數組
        val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
        //將偶數取出乘以10后再生成一個新的數組
        val res = for (e <- arr if e % 2 == 0) yield e * 10
        println(res.toBuffer)
       
        //filter過濾接收一個返回值為boolean的函數,過濾掉返回值為false的元素
        //map將數組中的每一個元素取出來(_)進行相應操作
        val r = arr.filter(_ % 2 == 0).map(_ * 10)
        println(r.toBuffer)
        
        //數組元素求和,最大值,排序
        println(arr.sum+":"+arr.max+":"+arr.sorted.toBuffer)
    }
    

    2.2 映射

    在Scala中,把哈希表這種數據結構叫做映射,類似于Java中的Map。

    在Scala中,有兩種Map:

    不可變Map:scala.collection.immutable.Map(可以存儲一些配置或參數供多個線程訪問,保證線程安全,具體還要結合業務實際場景),內容不可更改

    可變Map:scala.collection.mutable.Map==>類似于Java中的HashMap,可以進行put、get、remove等操作,內容可變

    map += ("c" -> 3) map += (("d",4)) 增加元素 -=移除元素 +/-增加或移除一個元素并返回一個新的集合

    注意:通常我們在創建一個集合時會用val這個關鍵字修飾一個變量,那么就意味著該變量的引用不可變,該引用中的內容是不是可變還取決于這個引用指向的集合的類型

    2.3 元組

    映射是K/V對偶的集合,對偶是元組的最簡單形式,元組可以裝著多個不同類型的值,元組是不可變的

    zip命令可以將多個值綁定在一起(將兩個數組/集合的元素一一對偶):

    注意:如果兩個數組的元素個數不一致,拉鏈操作后生成的數組的長度為較小的那個數組的元素個數

    對于元組val t = (1, 3.14, "Fred"),val (first, second, _) = t // second等于3.14

    2.4 集合

    Scala的集合有三大類:序列Seq、集Set、映射Map,所有的集合都擴展自Iterable特質。集合分可變(mutable)和不可變(immutable)兩種類型,immutable類型的集合初始化后長度和內容都不能改變(注意與val修飾的變量進行區別)

    2.4.1 Seq/List

    在Scala中列表要么為空(Nil表示空列表)要么是一個head元素加上一個tail列表。

    9 :: List(5, 2) :: 操作符是將給定的頭和尾創建一個新的列表【注意::: 操作符是右結合的,如9 :: 5 :: 2 :: Nil相當于 9 :: (5 :: (2 :: Nil))】

    def main(args: Array[String]): Unit = {
        //創建一個不可變集合
        val lt = List(1, 2, 3)
        /*//添加元素到lt前面生成一個新的List
        val lt2 = ("a", -1, 0) :: lt
        val lt3 = lt.::(0)
        val lt4 = 0 +: lt
        val lt5 = lt.+:(0)
        println(lt + "==>" + lt2 + "==" + lt3 + "==" + lt4 + "==" + lt5)
        val lt6 = lt :+ 4
        println("添加元素到后面:"+lt6 )*/
        //合并兩個集合,lt0在lt前面
        val lt0 = List(4,5,6,7)
        val lt7 = lt0.union(lt)
        val lt8 = lt0 ++ lt
        println(lt7 +":"+lt8 )
        println("lt0在lt后面"+lt ++ lt0)
        //將兩個集合中的元素一一綁定,如果元素數不一致以較少元素集合為準
        println(lt0.zip(lt).toMap)
        //將lt0插入到lt前面生成一個新的集合
        println(lt0 ++: lt)
        println(lt.:::(lt0))
      }
    def main(args: Array[String]): Unit = {
    //    構建一個可變列表,初始有3個元素1,2,3   alt+enter導包
        val lst0 = ListBuffer[Int](1,2,3)
        //創建一個空的可變列表
        val lst1 = new ListBuffer[Int]
        //向lst1中追加元素,注意:沒有生成新的集合
        lst1 += 4
        lst1.append(5)
        println(lst1)
        //將lst1中的元素最近到lst0中, 注意:沒有生成新的集合
        println(lst0 ++= lst1)
        //將lst0和lst1合并成一個新的ListBuffer 注意:生成了一個集合
        println(lst0 ++ lst1)
        //將元素追加到lst0的后面生成一個新的ListBuffer
        val lst3 = lst0 :+ 5
        println(lst3)
    }
    def main(args: Array[String]): Unit = {
    //    構建一個可變列表,初始有3個元素1,2,3   alt+enter導包
        val lst0 = ListBuffer[Int](1,2,3)
        //創建一個空的可變列表
        val lst1 = new ListBuffer[Int]
        //向lst1中追加元素,注意:沒有生成新的集合
        lst1 += 4
        lst1.append(5)
        println(lst1)
        //將lst1中的元素最近到lst0中, 注意:沒有生成新的集合
        println(lst0 ++= lst1)
        //將lst0和lst1合并成一個新的ListBuffer 注意:生成了一個集合
        println(lst0 ++ lst1)
        //將元素追加到lst0的后面生成一個新的ListBuffer
        val lst3 = lst0 :+ 5
        println(lst3)
      }
     def main(args: Array[String]): Unit = {
     /*   //創建一個List
        val lst0 = List(1,7,9,8,0,3,5,4,6,2)
        //將lst0中每個元素乘以10后生成一個新的集合
        val lst1 = lst0.map(_*10)
        val lst2 = for(i <- lst0) yield i * 10
        println(lst1 + ":" +lst2)
        //將lst0中的偶數取出來生成一個新的集合
        val lst3 = lst0.filter(_ % 2 == 0)
        val lst4 = for(i <- lst0 if(i % 2 == 0)) yield i
        println(lst3 + ":" +lst4)
        //將lst0排序后生成一個新的集合
        val lst5 = lst0.sorted//升序
        val lst6 = lst0.sortWith(_>_)//降序
        val lst7 = lst0.sortBy(x => x)//升序
        println(lst5 + ":" +lst6 + ":" +lst7)
        //反轉順序
        println(lst5.reverse)
        //將lst0中的元素4個一組,類型為Iterator[List[Int]]
        val it = lst0.grouped(4)
    //    println(it.toBuffer)
        //將Iterator轉換成List
        val lst8 = it.toList
        //將多個list壓扁成一個List
        println(lst8.flatten)
        //先按空格切分,再壓平
        val lines = List("hello tom hello jerry", "hello jerry", "hello kitty")
        lines.map(_.split(" ")).flatten
    lines.flatMap(_.split(" "))//
        //并行計算求和
        println(lst0.par.sum)
        println(lst0.par.reduce(_+_))//非指定順序
        println(lst0.par.reduceLeft(_+_))//指定順序
        //折疊:有初始值(無特定順序)
        val lst11 = lst0.fold(100)((x, y) => x + y)
        //折疊:有初始值(有特定順序)
        val lst12 = lst0.foldLeft(100)((x, y) => x + y) */
        //聚合
        val arr = List(List(1, 2, 3), List(3, 4, 5), List(2), List(0))
    //    println(arr.flatten.sum)
        /*先局部求和,再匯總
     _+_.sum:第一個下劃線是初始值和后面list.sum和,_.sum是list的和,非并行化時只初始化1次只攜帶1次
        _+_:初始值和list元素和的和 */
        val result = arr.aggregate(10)(_+_.sum,_+_)
        val res = arr.aggregate(10)((x,y)=>x+y.sum,(a,b)=>a+b)
        println(result+":"+res)
        val l1 = List(5,6,4,7)
        val l2 = List(1,2,3,4)
        //求并集
        val r1 = l1.union(l2)
        //求交集
        val r2 = l1.intersect(l2)
        //求差集
        val r3 = l1.diff(l2)
        println(r3)
      }
    

    2.4.2 Set

      def main(args: Array[String]): Unit = {
        //不可變Set
       /* val set1 = new HashSet[Int]()
        //將元素和set1合并生成一個新的set,原有set不變
        val set2 = set1 + 4
        //set中元素不能重復
        val set3 = set1 ++ Set(5, 6, 7)
        val set0 = Set(1,3,5) ++ set3
        println(set0)*/
        //創建一個可變的HashSet
        val set1 = new mutable.HashSet[Int]()
        //向HashSet中添加元素
        set1 += 2
        //add等價于+=
        set1.add(4)
        set1 ++= Set(1,3,5)
        println(set1)
        //刪除一個元素
        set1 -= 5
        set1.remove(2)
        println(set1)
      }
    

    3. 類、對象、繼承和trait

    3.1 類

    3.1.1 類的定義

    Scala中,可以在類中定義類、以在函數中定義函數、可以在類中定義object;可以在函數中定義類,類成員的缺省訪問級別是:public

    //在Scala中,類不用聲明為public
    //Scala源文件中可以包含多個類,所有這些類都具有公有可見性
    class Person {
      //val修飾的變量是只讀屬性,相當于Java中final修飾的變量,只提供get()
      val id = "1"
      //var修飾的變量,提供get()和set()
      var age: Int = 18
      //類私有字段,只有本類和本類的伴生對象可以訪問
      private var name = "zs"
      //對象私有字段只有本類能訪問
      private[this] val pet = "xq"
    }
    /**(單例對象,靜態對象)
      * 伴生對象:與class名相同,并且在同一個文件中*/
    object Person {
      def main(args: Array[String]): Unit = {
        val p = new Person
    //    p.id = "2"http://    p.pet
        println(p.id +":"+p.age+":"+p.name)
        p.name = "ls"
        p.age = 20
        println(p.age+":"+p.name)
      }
    }
    

    3.1.2 構造器

    Scala主要分主構造器和輔助構造器兩種:

    主構造器里面的變量會被執行,方法會被加載,調用的方法會被執行

    輔助構造器(相當于重載的構造函數)不可以直接調用超類的主構造器

    /**每個類都有主構造器,主構造器的參數直接放置類名后面,可以在主構造器中對字段賦值,對于主構造器中參數已賦值的在new的時候可以不再賦值
    private[com.bigdata] class Study{}:只有com.bigdata或其子包下的類能訪問Stu
    class Stu(name:String){}:構造參數name沒有val、var修飾
    相當于private[this] name:String ,只有本類能訪問
     class Stu private(name:String){}:private修飾主構造器(私有構造器),只有伴生對象能new */
     
    class Student(val name: String, val age: Int) {
      //主構造器會執行類定義中的所有語句
      println("執行主構造器")
      try {
        println("讀取文件")
        throw new IOException("io exception")
      } catch {
        case e: NullPointerException => println("打印異常Exception : " + e)
        case e: IOException => println("打印異常Exception : " + e)
      } finally {
        println("執行finally部分")
      }
      
      private var gender = "male"
      
      //用this關鍵字定義輔助構造器
      def this(name: String, age: Int, gender: String){
        //每個輔助構造器必須以主構造器或其他的輔助構造器的調用開始
    this(name, age)
        this.gender = gender
      }
    }
    

    3.1.3 Class

    Scala中類可以通過classOf[A]獲取類型,Object單例/伴生只能通過.getClass獲取。

    classOf和getClass區別:

    getClass方法得到的是Class[A]的某個子類,而classOf[A]得到是正確的 Class[A],但是去比較的話,這兩個類型是equals為true的。這種細微的差別,體現在類型賦值時,因為java里的Class[T]是不支持協變的,所以無法把一個 Class[_ < : A] 賦值給一個 Class[A]。

    類型檢查和轉換:

    Scala

    Java

    obj.isInstanceOf[C]:判斷obj是否屬于C類型

    obj instanceof C

    obj.asInstanceOf[C]:轉換

    (C)obj

    classOf[C]

    C.class

    3.2 對象

    3.2.1 單例對象和伴生對象

    1.單例對象
    在Scala中沒有靜態方法和靜態字段,但是可以使用object這個語法結構來達到同樣的目的。主要作用:
    1)存放工具方法和常量
    2)高效共享單個不可變的實例
    3)單例模式
    2.伴生對象
    單例對象,不需要new,用【類名.方法】調用單例對象中的方法
    伴生對象
    在scala的類中,與類名相同且與該類在同一個文件的對象叫伴生對象。類和伴生對象之間可以相互訪問私有的方法和屬性,但類的字段被private[this]修飾的只有本類能訪問
    

    3.2.2 應用程序對象

    Scala程序都必須從一個對象的main方法開始,可以通過擴展App特質,不寫main方法。

    object AppObjectDemo extends App{
      //不用寫main方法
      println("Scala")
    }
    

    3.2.3 apply和unapply方法

    通常我們會在類的伴生對象中定義apply方法,當遇到類名(參數1,...參數n)時apply方法會被調用。

    apply方法有點類似于java中的構造函數,接受構造參數變成一個對象。

    unapply方法就剛好相反,它是接收一個對象,從對象中提取出相應的值,主要用于模式匹配(后文闡述)中。

    def main(args: Array[String]) {
        //調用了Array伴生對象的apply方法
        //def apply(x: Int, xs: Int*): Array[Int]
        //arr1中只有一個元素5
        val arr1 = Array(5)
    //def apply[T: ClassTag](xs: T*): Array[T] = {}
        var arr2 = Array[Int](8)
        println(arr1.toBuffer)
        //new了一個長度為5的array,數組里面包含5個null(沒有指定泛型)
        var arr2 = new Array(5)
    }
    

    3.3 繼承和trait

    在Scala中繼承類的方式和Java一樣都是使用extends關鍵字,繼承多個類后面有with關鍵字。

    Scala中沒有接口,而是trait即特質,類似Java1.8中的接口,其中可以包含抽象方法也可以有已實現的方法。

    在Scala中重寫一個非抽象的方法(沒有被實現)必須使用override修飾符,抽象方法可以使用也可以不使用override。

    trait Flyable {
      def fly(): Unit = { println("I can fly")  }
    }
    abstract class Animal {
      def run(): Int
      val name: String
    }
    /*class Human extends Animal with Flyable
      class Human extends Flyable with其他trait(特質)
    */
    class Human extends Animal with Flyable {
      val name = "lz"
      //t1、t2、、tn打印n次ABC,t1=(1, 2, 3,4)(a->1,b->2,c->3,d->4)
      val t1, t2,t3, (a, b, c,d) = {
        println("ABC")
        (1, 2, 3,4)
      }
    //scala中重寫一個非抽象方法必須使用override關鍵字
      override def fly(): Unit = { println("123") }
    //重寫抽象方法可以使用也可以不使用override關鍵字
      def run(): Int = { 1 }
    }
    object Main {
      def main(args: Array[String]): Unit = {
        val h = new Human
        println(h.t1+":"+h.a+":"+h.b+":"+h.c+":"+h.t2)
      }
    }
    

    4. 模式匹配和樣例類

    4.1 模式匹配

    Scala有一個十分強大的模式匹配機制,可以應用到很多場合:如替代Java中的switch語句、類型檢查等。

    并且Scala還提供了樣例類,對模式匹配進行了優化,可以快速進行匹配。

    // 1. 匹配字符串
    import scala.util.Random
    object Case01 extends App {
      val arr = Array(1, 2, 3)
      val i = arr(Random.nextInt(arr.length))
      i match {
        case 1 => {println(i)}
        case 2 => {println(i)}
    //下劃線_:代表匹配其他所有類似于switch語句中default
        case _ => {println(i)}
      }
    }
    // 2. 匹配類型
    import scala.util.Random
    object Case02 extends App {
      val arr = Array("a", 1, -2.0, Case02)
      val elem = arr(Random.nextInt(arr.length))
      println(elem)
      elem match {
        case x:Int => {println("Int"+x)}
    //模式匹配時可以加守衛條件,如果不符合守衛條件,走case_
        case y:Double if(y>=0) => println("Double "+ y)
        case Case02 => {println("Int"+Case02)}
        case _ => {println("default")}
      }
    }
    // 3. 匹配數組
    object Case03 extends App {
      /*  val arr = Array(0, 3, 5)
        arr match {
          case Array(1,x,y) => println(x+":"+y)
          case Array(0) => println("only 0")
            //表示匹配首元素是0的數組
          case Array(0,_*) => println("0 ...")
          case _ => println("else")
        }*/
      /*  val lst = List(0,-1,1,2)
        //head首元素,tail除首元素之外的元素 take從1開始取
        println(lst.head+":"+lst.tail+":"+lst.take(1))
        lst match {
            //首元素0,Nil代表空列表
          case 0 :: Nil => println("only 0")
            //只有兩個元素
          case x :: y :: Nil => println(s"x:$x--y:$y")
          case 0 :: x => println(s"0...$x")//head和tail
          case _ => println("else")
        }*/
      val tup = (-1.2, "a", 5)
      tup match {
        //元組有幾個元素,case后跟的元組也要有幾個元素
        case (1, x, y) => println(s"hello 123 $x , $y")
        case (_, z, 5) => println(z) //前兩個元素為任意值
        case _ => println("else")
      }
      val lst1 = 9 :: (5 :: (2 :: Nil))
      val lst2 = 9 :: 5 :: 2 :: List()
      println(lst2+":"+lst1)//952:952
    }
    

    4.2 樣例類

    可用于模式匹配、封裝數據(多例)。case class多例,后面跟構造函數;case object是單例的:

    import scala.util.Random
    case class Task(id:String)
    case class HeartTime(private val time:Long)//構造case class可new可不new
    case object CheckTimeOut
    object Main {
        def main(args: Array[String]) {
            val arr = Array(CheckTimeOut, HeartBeat(88888), Task("0001"))
            val a = arr(Random.nextInt(arr.length))
           a match {
                case Task(id) => {println(s"$id")}//取id值 固定寫法
                case HeartTime(time) => {println(s"$time")}
                case CheckTimeOutTask => {
                    println("check")
                }
                
                //匹配其他情況
                case _ => prinln("do something")
             }
        }
    }
    

    5. 高階函數

    Scala中的高階函數包含:作為值的函數、匿名函數、閉包、柯里化等,可以把函數作為參數傳遞給方法或函數。

    5.1 作為值的函數

    定義函數時格式:val 變量名 = (輸入參數類型和個數) => 函數實現和返回值類型和個數。

    =:表示將函數賦給一個變量

    =>:左面表示輸入參數名稱、類型和個數,右邊表示函數的實現和返回值類型和參數個數

    5.2 匿名函數

    在Scala中,你不需要給每一個函數命名,沒有將函數賦給變量的函數叫做匿名函數

    5.3 方法轉換為函數

    在Scala中,法和函數是不一樣的,最本質的區別是函數可以做為參數傳遞到方法中,方法可以被轉換成函數。

    5.4 柯里化

    柯里化指的是將原來接收多個參數的方法或函數變成新的接收一個一個的參數的方法的過程。

    5.5 隱式轉換

    對類進行增強,關鍵字implicit。如Int沒有to(),而RichInt有to(),我們只需要在某個地方將Int轉為RichInt,然后在用的地方import隱式轉換就可以直接使用to(),示例:

    除了上述介紹的語法之外,像協變、逆變、actor也需要大家掌握。

    至于akka,如果大家使用的是老版本Spark,如Spark1.X,也建議結合actor好好學習,Spark老版本通信框架是用akka和netty結合的,當然后面完全是用netty了。

    構造器scala
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    前言Scala是以JVM為運行環境的面向對象的函數式編程語言,它可以直接訪問Java類庫并且與Java框架進行交互操作。正如之前所介紹,Spark是用Scala語言編寫的,Kafka server端也是,那么深入學習Scala對掌握Spark、Kafka是必備掌握技能。
    模糊測試的分類方法方式有好幾種,本文將著重介紹基于覆蓋率的模糊測試,因此只詳細介紹根據fuzzing策略的分類。基于fuzzing的策略,可將fuzzer分為基于定向的fuzzing和基于覆蓋率的fuzzing。定向模糊工具正是基于上訴原因應運而生。因此對于定向模糊測試工具而言,其目的旨在快速的測試特定的目標位置是否可能存在bug。
    電力工控系統是關系到電網安全穩定運行的重要領域。目前國網黑龍江電力有限公司已經建立起“安全分區、網絡專用、橫向隔離、縱向認證”的邊界安全防護體系。但在工控系統核心位置保護方面,還需考慮以下兩個問題:電力工控系統具有閉源特性,內部函數邏輯調用非開源;攻擊數據樣本極少,難以構建特征庫引擎。針對以上問題,從系統底層數據提取、運行狀態學習等方面開展研究,設計了涵蓋廠站、主站兩側的安全防御體系架構,為閉源電
    為了統一業界對關鍵術語和定義的認識和理解,規范術語和定義的使用,在工業和信息化部的指導下,工業互聯網產業聯盟對工業互聯網術語和定義進行了匯總、梳理、研究、討論,在此基礎上,編制形成了《工業互聯網術語和定義(1.0版本)》。
    2021年5月18日,《美國創新與競爭法案》(United States Innovation and Competition Act of 2021)通過,由芯片和ORAN5G緊急撥款、《無盡前沿法案》、《2021戰略競爭法案》、國土安全和政府事務委員會相關條款、《2021迎接中國挑戰法案》和其他事項六部分構成。該法案進一步強化了《無盡前沿法案》提出的在科技領域贏得與中國的競爭的目標,提出了十大
    (需要安裝Lombok插件和引?參構造去創建對象。編譯發現報錯不通過:解決方法方法一Lombok同時使?注解@Tolerate,讓Lombok在?成類的時候,對指定的構造函數不感知。在編譯期階段,當 Java 源碼被抽象成語法樹 之后,Lombok 會根據??個簡單的 Setter,我們的實現步驟是:?法的,因此Lombok提供了插件機制,?
    spring bean 的生命周期 實例化(instantiate), 用構造創建一個對象 字段賦值(populate) 初始化(initialize), 執行bean配置里的init方法或者InitializingBean#afterPropertiesSet方法 銷毀(destruct) 實例化和字段賦值一般都很快,但是一些重型的bean被IOC容器創建時,需要調用遠程服務或者執行耗時的操
    我們在使用金額計算或者展示金額的時候經常會使用 BigDecimal,也是涉及金額時非常推薦的一個類型。 BigDecimal 自身也提供了很多構造方法,這些構造方法使用不當可能會造成不必要的麻煩甚至是金額損失,從而引起事故資損。 事故 接下來我們看下收銀臺出的一起事故。 | 問題描述 收銀臺計算商品金額報錯,導致訂單無法支付。
    動態函數PHP中支持一個功能叫 variable function ,變量函數的意思。//最終是system;當一個變量后邊帶括號,那他就被視作一個函數。編譯器會解析出變量的值,然后會去找當前是否存在名為“system()”的函數并執行它。這里就不給實例了,很多免殺案例中都用到了這個特性。也是被瘋狂查殺的特征。回調函數回調函數,簡單來說就是一個函數不是由我直接調用,而是通過另一個函數去調用它。
    MyBatis-Plus是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。真實開發中,version(樂觀鎖),deleted、gmt_create、gem_mo
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类