主頁 >  其他 > scala學習筆記

scala學習筆記

2021-04-12 12:07:20 其他

scala語言:完全面向物件的語言(學習筆記)

hello world

object Hello {
  def main(args: Array[String]): Unit = {
    println("Hello World!")
  }
}


def:宣告
Unit:回傳值(java中的void)
//scala原始碼中包含了main方法,在編譯后自動形成了public static void main
//scala在編譯原始碼時,會生成兩個位元組碼檔案,靜態main方法執行另外一個位元組碼檔案中的成員main方法
//scala是完全面向物件的語言,那么沒有靜態的語法,只能通過 模擬 生成靜態方法
//編譯時將當前類生成一個特殊的類==>、、、、、、   然后創建物件來呼叫這個物件的main方法

//一般情況下,將加$類的物件,稱之為伴生物件
//伴生物件中的內容,都可以通過類名訪問,來模擬java中的靜態語法
//伴生物件的語法規則,使用object

//public static void main(String[]arrays){方法體}
//scala中沒有public關鍵字,默認所有的訪問權限都是公共的

//scala中沒有void關鍵字,采用特殊的物件來模擬void

//scala中宣告方法采用關鍵字def
//方法后面的小括號是方法的引數串列
//scala中引數串列的宣告和java不一樣

//java:String 引數名
//scala:  引數名:型別

//java中方法的宣告和方法體直接連接
//scala中方法的宣告和方法體通過=連接
//scala中將方法的回傳值型別放置在方法宣告的后面使用冒號連接
image-20210405173448657

scala注意事項:

1、scala源檔案以scala為擴展名

2、scala程式的執行入口是main()函式

3、scala嚴格區分大小寫

4、scala方法由一條條陳述句構成,每個陳述句后不需要分號(scala語言會在每行后自動加分號),體現出scala的簡潔性

5、如果在同一行有多條陳述句,除了最后一條陳述句不需要分號,其他陳述句需要分號,

package scala.chapter1
//列印字串
object scala_02 {
  def main(args: Array[String]): Unit = {
    //變數
    val name="加藤惠"
    val age=17;
    val url="先有圣人后有天,吾惠美如畫中仙"

    //列印字串
    println("測驗列印")
    //字串通過+號連接(類似java)
    println("name="+name+" age="+age+" url="+url)
    //print用法(類似C語言)字串通過%傳遞,(格式化輸出)
    printf("name=%s,age=%d,url=%s \n",name,age,url)
    //字串插值,通過$參考(類似PHP)
    println(s"name=$name,age=${age},url=$url")
    //保留2位小數
    println(f"name=$name,age=${age}%.2f,url=$url")
  }
}

//val修飾的物件參考可以改變,val修飾的則不可以改變,但物件的狀態(值)卻是可以改變的(比如:自定義物件、陣列、集合等等)

//Scala與Java有著相同的資料型別,在Scala中資料型別都是物件,也就是說scala沒有java中的原生(基本)型別

//地址不能變,但內容可變

package scala_chapter2

object scala_02 {
  def main(args: Array[String]): Unit = {
    //能省則省
    //scala為了讓開發程序變得簡單,可以將自動推斷出來的內容省略
    val username:String ="gafafa"
    val name="list"
    //宣告變數時,型別可以省略(這就是型別判斷)
    //型別確定后,就不能修改,說明scala是強型別語言
    //3.在宣告/定義一個變數時,可以使用var或者val來修飾,var修飾的變數可改變,val修飾的變數不可改
    //val修飾的物件屬性在變異后,等同于加上final
    //val修飾的物件參考可以改變,val修飾的則不可以改變,但物件的狀態(值)卻是可以改變的(比如:自定義物件、陣列、集合等等)
    //變數宣告時,必須有初始值(顯示初始化)

    val dog=new Dog()//地址不能變,但內容可變
    dog.name="ell";
    println(dog.name)
  }
}
class Dog{
  var name:String=""
}

//Scala與Java有著相同的資料型別,在Scala中資料型別都是物件,也就是說scala沒有java中的原生(基本)型別
/*
scala資料型別分為兩大類AnyVal(值型別)和AnyRef(參考型別)
注意:不管是AnaVal還是AnyRef都是物件
 */

//相對于java的型別系統,scala要復雜謝謝,也正是這復雜多變的型別系統才讓面向物件編程和函式式編程完美融合在一起


package scala_chapter2

object scala_datatype {
  def main(args: Array[String]): Unit = {
    //資料型別


    //scala是完全面向物件的語言,所以沒有基本資料型別
    val age:Int=20
    //byte,short,int long float double char boolean
    val b:Byte=10;
    val s:Short=10;
    val i:Int=10;
    val f :Float=10;
    val d:Double=10;
    val bln:Boolean=true;
    val c:Char='c';
    val ii:Integer=10
    //scala中10這個數字也是一個物件,可以呼叫方法

  }
}

整型的使用細節

1、scala各整數型別有固定的表數范圍和欄位長度,不受具體OS的影響,以保證Scala程式的可移植性

2.scala的整型 常量/字面量 默認為int型,宣告為Long型 常量/字面量 虛后加‘I’或‘L’

3.scala程式中變數常宣告為int型除非不足以表示大數,才使用Long

字符型別(char)

基本介紹

字符型別可以表時單個字符,字符型別是Char,16位無符號Unicode字符(2個位元組),區間值為U+0000到U+FFFF

var c1:Char='a'
var c2:Char='\t'
var c3:Char='你'
var c4:Char=97

boolean型別

1.布爾型別也叫Boolean型別,Boolean型別資料只允許取值true和false

2.Boolean型別占一個位元組

3.Boolean型別適于邏輯運算,一般用于程式流程控制:

if條件控制陳述句

while回圈控制陳述句

do-while回圈控制陳述句

for回圈控制陳述句

三個空型別

注意:null只能賦值給參考型別,不能給值型別

強制型別轉換

int i=(int)2.5

scala: var num:Int =2.7.toInt//面向物件

強轉符號只針對于最近的運算元有效,往往會使用小括號提升優先級

+,-號沒有byte和short之間的操作

識別符號概念:

1.Scala對各種變數、方法、函式等命名時使用的字符序列稱為識別符號

2.凡是自己可以起名字的地方都叫識別符號

識別符號的命名規則

Scala中的識別符號宣告,基本和java是一致的,但是細節上會有所變化

1.首字符為字母,后續字符任意字母和數字,美元符號,可后接下劃線

2.數字不可以開頭

3.首字符為運算子(比如+ - * /),后續字符也需跟運算子,至少一個

val ++ ="123"可行 在class中為 plusplus

val %#$=true 可行

val +a+=“123” 不可行

4.運算子(比作±*/)不能在識別符號中間和最后

5.用反導號(飄號)‘…’包括的任意字串,即使關鍵字(39個)也可以

val ‘private’:String="123"可行

scala中可以使用特殊符號作為識別符號,其實是將特殊符號在編譯時進行了轉換

scala中下劃線有特殊的用途,不能獨立當做變數名來使用(java中可以)

val Int =“123” 可行

運算子

1.算術運算子

算術運算子的運算規則和java一樣

Scala中沒有++、–運算子,需要通過+=、-=來實作同樣的效果

2.賦值運算子(同java)

3.比較運算子

如果兩個浮點數進行比較,應當保證資料型別一致.

4.邏輯運算子

5.位運算子

Scala不支持三目運算子 , 在Scala 中使用 if – else 的方式實作,

運算子描述實體
&按位與運算子(a & b) 輸出結果 12 ,二進制解釋: 0000 1100
|按位或運算子(a | b) 輸出結果 61 ,二進制解釋: 0011 1101
^按位異或運算子(a ^ b) 輸出結果 49 ,二進制解釋: 0011 0001
~按位取反運算子(~a ) 輸出結果 -61 ,二進制解釋: 1100 0011, 在一個有符號二進制數的補碼形式,
<<左移動運算子a << 2 輸出結果 240 ,二進制解釋: 1111 0000
>>右移動運算子a >> 2 輸出結果 15 ,二進制解釋: 0000 1111
>>>無符號右移A >>>2 輸出結果 15, 二進制解釋: 0000 1111
類別運算子關聯性
1() []左到右
2! ~右到左
3* / %左到右
4+ -左到右
5>> >>> <<左到右
6> >= < <=左到右
7== !=左到右
8&左到右
9^左到右
10|左到右
11&&左到右
12||左到右
13= += -= *= /= %= >>= <<= &= ^= |=右到左
14,左到右

鍵盤輸入陳述句

在編程中,需要接收用戶輸入的資料,就可以使用鍵盤輸入陳述句來獲取,InputDemo.scala

java:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-saeDxVn8-1618126542281)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406081620354.png)]

scala:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-d6zc2oAW-1618126542283)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406081635513.png)]

scala核心編程

程式控制流

在scala中沒有switch,而是使用模式匹配來處理,

范圍資料回圈方式1
基本案例
for(i <- 1 to 3){
print(i + " ")
}
println()
說明
i 表示回圈的變數, <- 規定好 to 規定
i 將會從 1-3 回圈, 前后閉合 (包括1 和 3)

for(i <- 1 until 3) {
print(i + " ")
}
println()
說明:
這種方式和前面的區別在于 i 是從1 到 (3-1)
前閉合后開的范圍,和java的arr.length() 類似
for (int i =0; i < arr.lenght(); i++ ){}

for(i <- 1 to 3 if i != 2) {
print(i + " ")
}
println()

基本案例說明
回圈守衛,即回圈保護式(也稱條件判斷式,守衛),保護式為true則進入回圈體內部,為false則跳過,類似于continue

引入變數

for(i <- 1 to 3; j = 4 - i) {
print(j + " ")
}

對基本案例說明
沒有關鍵字,所以范圍后一定要加;來隔斷邏輯

上面的代碼等價

for (i <- 1 to 3) {
var j = 4 – i
print(j + “ “)
}

for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j)
}

對基本案例說明
沒有關鍵字,所以范圍后一定要加;來隔斷邏輯
上面的代碼等價

for(i <- 1 to 3){

? for(i <- 1 to 3){

? println(“ok”)

}

}

val res = for(i <- 1 to 10) yield i * 2
println(res)

輸出結果:Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

對基本案例說明
將遍歷程序中處理的結果回傳到一個新Vector集合中,使用yield關鍵字

Scala內置控制結構特地去掉了break和continue,是為了更好的適應函式化編程,推薦使用函式式的風格解決break和contine的功能,而不是一個關鍵字

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hWfDH7rg-1618126542285)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406085506400.png)]

函式式編程

基礎

1.函式定義/宣告

2.函式運行機制

3.遞回

4.程序

5.惰性函式和例外

高級

1.值函式(函式字面量)

2.閉包

3.應用函式

4.抽象控制…

在scala中,函式式編程和面向物件編程融合在一起,學習函式式編程式需要oop的知識,同樣學習oop需要函式式編程的基礎,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mUY91sxy-1618126542287)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406091314897.png)]

1.在scala中,方法函式幾乎可以等同(比如他們的定義、使用、運行機制都是一樣的),只是函式的使用方式更加的靈活多樣

2.函式式編程是從編程方式(范式)的角度來談的,可以這樣理解:函式式編程把函式當成一等公民,充分利用函式、支持的函式的多種使用方式,

比如:

在scala中,函式式一等公民,像變數一樣,既可以作為函式的引數使用,也可以將函式賦值給一個變數,函式的創建不用依賴于類或者物件,而在java當中,函式的創建要依賴于類、抽象類或者介面

3.面向物件編程是以物件為基礎的編程方式

4.在scala中函式式編程和面向物件編程融合在一起了

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Xvuv8HPr-1618126542289)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406091938031.png)]

函式式編程介紹:

函式式編程是一種“編程范式”(programming paradigm)

它屬于“結構化編程”的一種,主要思想是吧運算程序盡量寫成一系列嵌套的函式調動,

函式式編程中,將函式也當做資料型別,因此可以接受函式當做輸入(引數)和輸出(回傳值),(增強了編程的粒度)

函式式編程中,最重要的就是函式,

def 函式名 ([引數名: 引數型別], …)[[: 回傳值型別] =] {
陳述句… //完成某個功能
return 回傳值
}
1.函式宣告關鍵字為def (definition)
2.[引數名: 引數型別], …:表示函式的輸入(就是引數串列), 可以沒有, 如果有,多個引數使用逗號間隔
3.函式中的陳述句:表示為了實作某一功能代碼塊
4.函式可以有回傳值,也可以沒有
5.回傳值形式1: // def 函式名(引數串列) : 資料型別 = {函式體} // 回傳值確定,清晰
6.回傳值形式2: // def 函式名(引數串列) = {函式體} // 有回傳值, 型別是推斷出來的
7.回傳值形式3: // def 函式名(引數串列) {函式體} // 無回傳值 Unit
8.如果沒有return ,默認以執行到最后一行的結果作為回傳值

函式遞回需要遵守的原則(總結):

1.程式執行一個函式時,就創建一個新的受保護的獨立空間(新函式堆疊楨)

2.函式的區域變數是獨立的,不會相互影響

3.遞回必須向退出遞回的條件逼近,否則就是無線遞回

4,當一個函式執行完畢,或者遇到return,就會回傳,遵守誰呼叫,就將結果回傳給誰

函式的形參串列可以是多個, 如果函式沒有形參,呼叫時 可以不帶()

形參串列和回傳值的資料型別可以是值型別和參考型別,

Scala中的函式可以根據函式體最后一行代碼自行推斷函式回傳值型別,那么在這種情況下,return關鍵字可以省略

def getSum(n1: Int, n2: Int): Int = {
n1 + n2
}

def getSum(n1: Int, n2: Int) = {
n1 + n2
}

因為Scala可以自行推斷,所以在省略return關鍵字的場合,回傳值型別也可以省略

如果函式明確使用return關鍵字,那么函式回傳就不能使用自行推斷了,這時要明確寫成 : 回傳型別 = ,當然如果你什么都不寫,即使有return 回傳值為()

如果函式明確宣告無回傳值(宣告Unit),那么函式體中即使使用return關鍵字也不會有回傳值

如果明確函式無回傳值或不確定回傳值型別,那么回傳值型別可以省略(或宣告為Any)

def f3(s: String) = {
if(s.length >= 3)
s + “123”
else
3
}

def f4(s: String): Any = {
if(s.length >= 3)
s + “123”
else
3
}

Scala語法中任何的語法結構都可以嵌套其他語法結構(靈活),即:函式/方法中可以再宣告/定義函式/方法,類中可以再宣告類,

Scala函式的形參,在宣告引數時,直接賦初始值(默認值),這時呼叫函式時,如果沒有指定實參,則會使用默認值,如果指定了實參,則實參會覆寫默認值

如果存在多個引數,每一個引數都可以設定默認值,那么這個時候,傳遞的引數到底是覆寫默認值,還是賦值給沒有默認值的引數,就不確定了(默認按照宣告順序[從左到右]),在這種情況下,可以采用帶名引數

def mysqlCon(url:String = “jdbc:mysql://localhost",
port : Int = 3306,
user: String = “root”,
pwd : String = “root”): Unit = {
println(“host=" + host)
println(“port=” + port)
println(“user=” + user)
println(“pwd=” + pwd)
}

def f6 ( p1: String = “v1”, p2: String ) {
println(p1 + p2);
}
f6(“v2” ) 不行
f6(p2=“v2”) 不行

scala支持可變引數

說明:
args 是集合, 通過 for回圈 可以訪問到各個值,

可變引數需要寫在形參串列的最后,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3LJbBBZ8-1618126542290)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406102409298.png)]

傳值呼叫和傳名呼叫

var money = 100
def buy(): Int = {

? money -= 10

? money

}

def test1(a: Int) = {

? println(a)

? println(a)

}

def test2(a: => Int) = {

? println(a)

? println(a)

}

def main(args: Array[String]): Unit = {

? test1(buy)
? test2(buy)
}

高階函式

將其他函式作為引數或回傳值為一個函式的函式函式(higher-order function)

// 函式的第一個引數型別是另一個函式
def apply(f: Int => String, v: Int) = f(v)

def fmtInt(n: Int) : String = “[整數值{” + n + “}]”

def main(args: Array[String]): Unit = {

println(apply(fmtInt, 1200))

}

 //scala可以采用自動推動功能來簡化函式的宣告
    /*
    1.如果函式宣告時,明確無回傳值,,那么即使函式體中有return也沒用


     */
//    def test(): Unit ={
//      return "張三"
//    }
//    println(test())

    //如果將函式體的最后一行打碼進行回傳,那么return關鍵字可以省略

    //如果明確函式沒有回傳值,那么等號可以省略,省略后,編譯器不會醬函式體最后一行代碼作為回傳值
    //如果函式沒有引數串列,可以省略小括號,呼叫時不能加小括號
    //如果函式沒有引數串列,但沒有省略小括號,呼叫時可加可不加

    //匿名函式
    ()->(println("bbbbbb"))
//函式式編程
    //可變引數
    def test(name:String*): Unit ={
      println(name)
    }
test("1","2","3")
    //默認引數
    def test1(name:String,age:Int=20): Unit ={
      println(s"${name} - ${age}")
    }
    test1("zhangsan")
    test1("杭三",30)
    //呼叫函式時,從前到后,從左到右

函式在scala中可以做任何事情

函式可以賦值給變數

函式可以作為函式的引數

函式可以作為函式的回傳值

def f(): Unit ={
  println("fff")
}

def f0()={
  //回傳一個函式
  //直接回傳函式,但不執行,需要增加特殊符號:_
  f _
}

f0()()//將函式作為引數回傳
def f1(i:Int)={
  def f2(j:Int): Int ={
    //println("f2f2f2f2")
    i*j
  }
  f2 _
}


println(f1(10)(20))



//函式柯里化(閉包)
    //一個函式在實作邏輯時,將外部的變數引入到函式的內容,改變了這個變數的生命周期,稱之為閉包
    def f3(i:Int)(j:Int):Int={
        i*j
    }

    println(f3(10)(20))



//將函式作為引數傳遞給另外一個引數,需要采用特殊的宣告方式
    //()=>Unit
    //引數串列=>回傳值型別
        def f4(f :()=>Int): Int ={
      f()+10
    }

    def f5():Int={
      5
    }
    println(f4(f5))

補充:

堆疊上分配

逃逸分析

def f7(f:(Int)=>Unit): Unit ={
  f(10)
}
    def f8(i:Int): Unit ={
      println(i)
    }
    f7(f8)
def f7(f:(Int)=>Unit): Unit ={
  f(10)
}
    f7((i)=>{println(i)})

惰性(延遲加載)

object test_lazy {
  def main(args: Array[String]): Unit = {
    lazy val res=sum(10,20)+"是結果"
    println("___________")
    println("____________")
    println("______________")
    println("______________")

    println(res)
  }
  def sum(a:Int,b:Int): Int ={
    println("執行了")
    a+b
  }


}

面向物件編程

//面向物件
//TODO scala是一個完全面向物件的語言
//scala中的包的宣告方式默認和java是一致的,但是有其他的使用方式
//1)在同一個原始碼檔案,可以多次宣告
//宣告的類在最后的那個包中
//原始碼中的類所在的位置不需要和包的路徑相同
//2)scala中所有的語法都可以進行嵌套
//  package可以使用小括號,小括號內部生命的類在這個包中,之外宣告的類不在這個包中
//3)scala中可以宣告父包和子包,父包中的類,子類可以直接訪問,不需要引入,其實就是作用域的概念
//4)scala中package可以宣告類,但是無法宣告變數和函式(方法)
//5)為了彌補包的不足,使用了包物件的概念
//包物件中可以宣告屬性和方法
//


object test_01 {
  def main(args: Array[String]): Unit = {
    var user:User=new User()

    user.username="zhangsan"
    println(user.username)


  }
}
//宣告類
class User{
  //宣告屬性
  var username:String=_

  var age:Int = _

  //方法
  def login():Boolean={
    true
  }
}
/*
import用于匯入類
import可以在任何地方使用
import可以匯入一盒包中所有的類,采用_代替*
import匯入相同包中的多個類,采用大括號進行包含處理

 */

import java.util.{ArrayList,List,Date}


//scala中如果想要從最開始的包中查找類,需要增加絕對路徑,使用_root_開頭



[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wDHkueWu-1618126542290)(D:\scala\030_Scala\4.視頻\呼叫問題.jpg)]

在類中宣告屬性,默認為是私有的,但是底層提供了公共的setter和getter方法,所以可以正常呼叫

如果給屬性增加private修飾符,那么屬性無法在外部訪問,因為底層神生成的setter和getter方法都是私有的,

如果宣告的屬性使用val,那么屬性是私有的,底層只提供getter方法,沒有setter方法

為了和java的bean規范統一,scala提供了注釋,生成java中對應的set,get方法

伴生物件(靜態)可以訪問伴生類(成員)的私有屬性

創建伴生類物件,需要提供特殊的方法,實作相應的功能

scala自動識別apply方法,用于創建伴生類物件

val student=Student(“zhangsan”)

println(student)

構造方法

函式和類中 = 在確定沒有任何回傳值的情況下可以省略

package scala_chapter06

object scala_son {
  def main(args: Array[String]): Unit = {
    //TODO 創建物件
    val user=new User09("路人女主")
    print(user)
  }
}
//TODO scala的構造方法分為2類:主構造方法和輔助構造方法
/*
scala構建物件可以通過輔助構造方法創建,但是必須呼叫主構造方法
scala是完全面向函式的語言,所以類也是函式
類是一種函式,可以使用小括號作為函式的引數串列
類所代表的函式其實就是這個類的構造方法
默認情況下,scala也是給類提供無參構造方法
在類的后面宣告的構造方法就是主構造方法
 */
class User09(s:String) {
  //TODO 類體 & 構造方法體
  println(s)

  //宣告輔助構造方法,方法名為this
  def this(){
    this("wangwu")
  }
  
}
類的繼承和抽象類


package scala_chapter06

object scala_class {
  def main(args: Array[String]): Unit = {
//    val user=new User10()
//    user.name
    val uset=new User10
    uset.test()

  }
}
//宣告類
/*
父類,繼承
類可以宣告為抽象的 abstract

 */
abstract class Person{
    var name:String= _

  //宣告抽象方法,方法只有宣告沒有實作,不需要abstract宣告
  def test()
}

class User10 extends Person {
  //重寫抽象方法,補全方法
  override def test(): Unit = {
    print("路人女主")

  }
}

動態系結



package scala_chapter06

object scala_dump {
  def main(args: Array[String]): Unit = {
    val user=new User11
    user.test1()
  }
}
abstract class Person{
  //scala找那個屬性也可以重寫,因為屬性可以抽象
  var name:String =_
  //不完整,為抽象屬性
  //TODO 屬性只有宣告,而沒有初始化,那么就是抽象屬性
  //抽象屬性在編譯為class檔案時,不產生屬性,但是產生抽象的getter方法
  var sex:String
  //宣告抽象方法,方法只有宣告,沒有實作,不需要abstract
  def test()

  def test1():Unit={

  }
}
class User11 extends Person{

  override def test(): Unit = {

    print("路人女主")
  }
  //TODO scala如果子類重寫父類的方法(不是抽象),需要增加override關鍵字
  override def test1(): Unit ={
    print("clannad")
  }


  //屬性可以被覆寫(重寫),但是不能重寫父類var宣告的變數
  override var sex: String = _
}
package scala_chapter06

object scala_lei_con {
  def main(args: Array[String]): Unit = {
    val user=new User13("123")

    println(user.s)
  }
}
//類構造方法的引數的作用域默認為整個類的主體,但是如果想要引數作為屬性來使用,可以采用特殊方式宣告
class User13(var s:String){
  
}

特質

package scala_chapter06
/*
介面
scala中沒有介面的概念沒有interface,但是有特質
trait,類似于介面
 */

object scala_jieko {
  def main(args: Array[String]): Unit = {
    val user=new User14
    print(user)
  }
}
//宣告特質
trait Testtrait{
}

trait Testtrait1{
}
class Person14{
}
//特質可以繼承,所以使用extend關鍵字
//如果類繼承多個特質,采用with連接
//如果類同時存在父類和特質,依然采用繼承方式,但是繼承的是父類,連接特質
class User14 extends Testtrait with Testtrait1 {

}
package scala_chapter06

object TEST_scala_trait {
  def main(args: Array[String]): Unit = {
    //java中的介面無法直接構建物件
    //scala中的特質也無法構建物件
    /*
    scala中的特質可以執行代碼
    scala特質中宣告的屬性和方法都可以在混入的類中呼叫
     */

    val user=new User15()
    user.test()
  }
}
trait TestTrait15{
    //println("jkjkjkjkjk")
//  var username:String="jkjkjkjk"
//
//  def test(): Unit ={
//    println("沙優")
//  }
  //特質中可以宣告抽象方法
  def test()


}

class Person15{

}

class User15 extends Person15 with TestTrait15{
  override def test(): Unit = {
    println("111111")

  }
}
package scala_chapter06

//TODO  特質和父類沒有關系,只和當前混入的類有關,所以,在呼叫時,父類先執行,然后混入當前的特質再執行,然后當前類再執行
//如果父類混入了相同特質,那么該特質的代碼只會執行一遍


object scala_con_con {
  def main(args: Array[String]): Unit = {
    val user=new User__2
  }
}

trait user_000{
  println("trait code")
}
class User_1{
  println("paresen _code")
}

class User__2 extends User_1 with user_000 {
  println("child code")
}
object scala_con_con {
  def main(args: Array[String]): Unit = {
    val ttt=new test_000
    ttt.insert()
  }
}

trait  Operate{
  println("Operate...")

  def insert(): Unit ={
    println("插入資料")
  }
}


trait MySql extends Operate{
  println("Mysql...")

  override def insert(): Unit ={
    println("向資料庫")
    super.insert()
  }
}
//特質可以繼承其他特質
//特質可以多載父特質的方法
trait File extends Operate{
  println("File...")

  override def insert(): Unit ={
    println("向檔案中")
    super.insert()
  }
}
//多特質混入時代碼執行順序為從左到右,如果有父特質,會優先執行
//多特質混入時,方法的呼叫為從右到左
//特質中super的關鍵字指代上一級,而不是父特質


class test_000 extends MySql with File{

}
/*
執行結果

Operate...
Mysql...
File...
向檔案中
向資料庫
插入資料



 */

隱式轉換

package scala_chapter07

object scala01_Transform {
  def main(args: Array[String]): Unit = {
    /*
   自動轉換-隱式轉換
   scala默認的情況下支持數值型別的自動轉換
   byte->short->int -> long
   scala默認的情況下支持多型語法中的型別自動轉換
   child ->parent->trait(interface)
   scala也允許開發人員自定義型別轉換規則
   將兩個無關的型別通過編程手段讓他們可以自動轉換
    */
    implicit def transfrom(d:Double):Int={
    d.toInt
    }

    //OCP
    val i:Int=5.0

    print(i)

  }
}

OHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!

package scala_chapter07

object Scala02_Transform1 {
  def main(args: Array[String]): Unit = {
    implicit def transform(mysql:Mysql):Operater={
      new Operater
    }
    var mysql=new Mysql
    mysql.select()
    mysql.delete()
  }
}

class Operater{
  def delete(): Unit ={

  }
}

class Mysql{
  def select(): Unit ={

  }
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ErSc7yJa-1618126542291)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409073811830.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TgSxNH7u-1618126542292)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409073919560.png)]

object Scala03_Transform2 {
  def main(args: Array[String]): Unit = {

    def test(implicit  name:String="加藤惠"): Unit ={
      println("Hello"+name)
    }

    test

  }
}
object Scala03_Transform2 {
  def main(args: Array[String]): Unit = {

    //隱式值
    implicit val username:String ="路人女主"
    //隱式引數
    def test(implicit  name:String="加藤惠"): Unit ={
      println("Hello"+name)
    }
    test
  }
}



輸出結果:Hello 路人女主
object Scala03_Transform2 {
  def main(args: Array[String]): Unit = {

    //隱式值
    implicit val username:String ="路人女主"
    //隱式引數
    def test(implicit  name:String="加藤惠"): Unit ={
      println("Hello"+name)
    }
    //test
    test()
  }
}

輸出結果:hello加藤惠
package scala_chapter07

object Scala04_Transform3 {
  def main(args: Array[String]): Unit = {
    val user4=new User4

    user4.insert()
    user4.delete()
  }


  class User4{

    def insert(): Unit ={

    }

  }
  
  implicit class Person4(u:User4){
    def delete(): Unit ={
      
    }
  }


}

隱式類使用的特點:

1.其所帶的構造引數有且只能有一個

2.隱式類必須被定義在“類”或“伴生物件”或“包物件”里,即隱式類不能是頂級的

3.隱式類不能是case class

4.作用域內不能有相同名稱的識別符號

隱式的轉換時機

1.當方法中的引數的型別與目標型別不一致時(二次編譯)

2.當物件呼叫所在類中不存在的方法或成員時,編譯器會自動將物件進行隱式轉換(根據型別)

package scala_chapter07

import scala_chapter07.Scala04_Transform3.User4

object Scala04_Transform3 {
  def main(args: Array[String]): Unit = {
    val user4=new User4

    user4.insert()
    user4.delete()
  }
  class User4 extends Test {
    def insert(): Unit ={

    }
  }

}
trait Test {

}
//創建一個伴生物件
object Test{
  implicit class Person4(u:User4){
    def delete(): Unit ={

    }
  }
}

陣列

object Scala02_Array {
  def main(args: Array[String]): Unit = {
    //scala中的陣列,使用array物件實作,宣告使用中括號宣告陣列的型別
    //Array[String]
    //scala可以使用簡單的方式創建陣列
    //Array可以通過apply方法來創建陣列物件
    val ints = Array(1, 2, 3, 4)
    //訪問陣列:使用小括號,增加索引的方式來訪問陣列
    println(ints(0))//1
    //陣列長度
    println(ints.length)//4
    println(ints)//[I@28f67ac7
    //將陣列轉化為字串列印出來

    println(ints.mkString(","))//1,2,3,4
    //將陣列中的每個元素列印
    for(elem <- ints){
      println(elem)
    }


    def printXXX(i:Int): Unit ={
      println(i)
    }
    //foreach方法會將陣列中的每一個元素進行回圈遍歷,執行指定函式實作邏輯
    //ints.foreach(printXXX)
    ints.foreach((i:Int)=>{print(i+",")})//1,2,3,4,
    ints.foreach(print(_))
    ints.foreach(print)


    //增加元素
    ints.update(1,5)
    println(ints.mkString(","))


  }
}
//不可變陣列
    //增加元素
    //產生了一個新的陣列,不會對原有陣列造成影響
    val ints1:Array[Int]= ints:+(5)
    println(ints1.mkString(","))
    //
    //修改資料
//    ints.update(1,5)
//    println(ints.mkString(","))
    //不可變陣列
    //增加元素
    //產生了一個新的陣列,不會對原有陣列造成影響
    val ints1:Array[Int]= ints:+(5)
    println(ints1.mkString(","))
    //
    //修改資料
    ints.update(1,5)
    println(ints.mkString(","))


    //可變陣列
    val arrayBuffer: ArrayBuffer[Int] = ArrayBuffer(5,6,7,8)
    // println(arrayBuffer(0))//5
     //修改值
    arrayBuffer(0)=9
    //將陣列轉化為字串
    println(arrayBuffer.mkString(","))
     //回圈遍歷
     //arrayBuffer.foreach(println)
     //增加資料
     //val unit: Unit = arrayBuffer.insert(9)
     //回傳是unit說明這是可變的
    val buffer:ArrayBuffer[Int]=arrayBuffer+=(9)
   println(arrayBuffer == buffer)//true
   arrayBuffer.foreach(println)
   val i:Int = arrayBuffer.remove(1)
   println("i = "+i )
   println(arrayBuffer.mkString(","))
     /*
     i = 6
     5,7,8
      */
     val unit: Unit = arrayBuffer.remove(1, 2)
    println(arrayBuffer.mkString(","))//5,8

    //可變陣列和不可變陣列的轉換
    val buffer: mutable.Buffer[Int] = ints.toBuffer
    val array: Array[Int] = arrayBuffer.toArray

scala集合基本介紹

1.scala同時支持不可變集合和可變集合

//佇列

import scala.collection.mutable

object Scala04_queue {
  def main(args: Array[String]): Unit = {
    val queue=  mutable.Queue(1,2,3,4)
    println("add before "+queue)
    //添加
    queue.enqueue(5)
    println("add after "+queue)
    //洗掉
    val i:Int = queue.dequeue()
    println("i="+i)
    println("delete after "+queue)

  }
}
set集合

object Scala05_set {
  def main(args: Array[String]): Unit = {
    var set=Set(1,2,3,4,5,6,7,8,8,9)
    println(set)//Set(5, 1, 6, 9, 2, 7, 3, 8, 4)  set為無序的,不可重復的
    //默認scala提供的set集合就是不可變的

    //增加資料
    println(set+11)//Set(5, 1, 6, 9, 2, 7, 3, 11, 8, 4)
    //洗掉資料
    println(set-11)//Set(5, 1, 6, 9, 2, 7, 3, 8, 4)
  }

}

元組

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JazBx3Cw-1618126542293)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409143308232.png)]

注意:從1開始

注意:遍歷部分

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-miL0vdpd-1618126542293)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409143715471.png)]

object Scala07_tuble {
  def main(args: Array[String]): Unit = {
    val tuple1=(1,2,3,"gasdfsa","發斯蒂芬家")
    println(tuple1)//(1,2,3,gasdfsa,發斯蒂芬家)

    var tup1=2->"two"
    println(tup1)//(2,two)

    //元組的使用
    println(tuple1._1)//1
    println(tuple1.productElement(0))//1   訪問元組的第一個元素,從0開始


    //遍歷
    for (m<-tuple1.productIterator){
      println(m)
    }

  }
}

Map

HashMap

java中:

HashMap 是一個散串列(陣列+鏈表),它存盤的內容是鍵值對(key-value)映射,Java中的HashMap是無序的,key不能重復

Scala中的Map 和Java類似,也是一個散串列,它存盤的內容也是鍵值對(key-value)映射,Scala中不可變的Map是有序的,可變的Map是無序的,

如果key存在,回傳key對應的值,
如果key不存在,回傳默認值,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nWve4OMe-1618126542294)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409145456245.png)]

val stringToInt: mutable.HashMap[String, Int] = mutable.HashMap(("A", 1), ("B", 2))

println(stringToInt("A"))//1

stringToInt += ("C"->3)

println(stringToInt)//Map(A -> 1, C -> 3, B -> 2)

stringToInt-=("C")
println(stringToInt)

set的其他方法

序號方法描述
1def +(elem: A): Set[A]為集合添加新元素,并創建一個新的集合,除非元素已存在
2def -(elem: A): Set[A]移除集合中的元素,并創建一個新的集合
3def contains(elem: A): Boolean如果元素在集合中存在,回傳 true,否則回傳 false,
4def &(that: Set[A]): Set[A]回傳兩個集合的交集
5def &~(that: Set[A]): Set[A]回傳兩個集合的差集
6def ++(elems: A): Set[A]合并兩個集合
7def drop(n: Int): Set[A]]回傳丟棄前n個元素新集合
8def dropRight(n: Int): Set[A]回傳丟棄最后n個元素新集合
9def dropWhile(p: (A) => Boolean): Set[A]從左向右丟棄元素,直到條件p不成立
10def max: A //演示下查找最大元素
11def min: A //演示下查找最小元素
12def take(n: Int): Set[A]回傳前 n 個元素
import scala.collection.immutable.HashMap
import scala.collection.mutable
import scala.collection.mutable.HashMap
object Scala08_HashMap {
  def main(args: Array[String]): Unit = {
    val map= mutable.Map(("A",1),("B",2),("C",3),("D",4))

//    println(map.mkString(","))//A -> 1,C -> 3,B -> 2
//
//    println(map.get("A"))//Some(1)
//    println(map.get("X"))//None
//
//    println(map.getOrElse("X","X"))

    map-=("B")
    println(map)//Map(D -> 4, A -> 1, C -> 3)
    

  }
}

容器進階:

請將List(3,5,7) 中的所有元素都 * 2 ,將其結果放到一個新的集合中回傳,即回傳一個新的List(6,10,14), 請撰寫程式實作.

1import scala.collection.mutable.{HashMap, ListBuffer}
object Scala08_HashMap {
  def main(args: Array[String]): Unit = {
    val list = List(3,5,7)
    val buffer = ListBuffer[Int]()
    for(i <- list){
      buffer.append(i*2)
    }
    println(buffer.mkString(","))


  }
}


2val list=List(3,5,7)
    def f1(i:Int): Int ={
      2*i
    }
    val list2=list.map(f1)
    println(list2)

在Scala中可以通過map映射操作來解決:將集合中的每一個元素通過指定功能(函式)映射(轉換)成新的結果集合這里其實就是所謂的將函式作為引數傳遞給另外一個函式,這是函式式編程的特點

//元組
    //Map(k -> v)
    //將無關的資料當成整體來使用
    //使用小括號將資料關聯在一起,形成一個整體
    //元組中最多的元素資料個數是22
    val tuple:(String ,Int, String)=("張三",11111,"xxxxx")
    //訪問元組中的資料,呼叫元組中的資料,呼叫相應的順序編號
    println(tuple._1)
    println(tuple._2)


    //回圈遍歷
//    for (elem <- tuple.productIterator) {
//      println(elem)
//    }
    //如果元組中元素個數為2,那么稱之為對偶,類似于Map中鍵值對
    val tuple1 = (1, "張三")


    val intToString: Map[Int, String] = Map((1, "bell"))
    intToString.foreach(tuple1=>{println(tuple1)})
  }
}

class User{
  var username:String=_
  var age:Int=_
}
集合方法

object Scala07_Method {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4,3,3)
    //求和
    println("sum="+list.sum)
    //最大值
    println(list.max)
    //最小值
    println(list.min)
    //乘積
    println(list.product)
    //反轉
    println(list.reverse)
    //
    //list.reduce()
    //TODO 分組(通過制定函式的回傳值分組)
//    val intToInts: Map[Int, List[Int]] = list.groupBy(x => x)
//    intToInts.foreach(t=>{println(t._1+"="+t._2)})
    val strings: List[String] = List("11", "35", "14", "26")
//    val stringToStrings: Map[String, List[String]] = strings.groupBy(s => {
//      s.substring( 0, 1)
//    })
//
//    stringToStrings.foreach(t=>{println(t._1+"="+t._2)})

    //TODO 對偶數分組
    val intToInts: Map[Int, List[Int]] = list.groupBy(i => {
      i % 2
    })
    intToInts.foreach(t=>{println(t._1+"="+t._2)})
    //TODO 排序(按照指定規則排序)
//    val ints: List[Int] = list.sortBy(x => x)
//    println(ints.mkString(","))
//val strings1: List[String] = strings.sortBy(s => {
//  s.substring(1)
//})
//
//    println(strings1.mkString(","))

    //TODO sortWith(降序)
//    val ints: List[Int] = list.sortWith((x, y) => {
//      x > y
//    })
//    println(ints.mkString(","))
val strings1: List[String] = strings.sortWith((left, right) => (left.substring(1) > right.substring(1)))
    println(strings1.mkString(","))

    //TODO 迭代
    for (elem <- list.iterator) {
      println(elem)
    }

    //TODO map映射
    //x=>(x,x)
    val tuples: List[(Int, Int)] = list.map(x => (x, 1))
    val intToTuples: Map[Int, List[(Int, Int)]] = tuples.groupBy(t => t._1)
    val intToInt: Map[Int, Int] = intToTuples.map(t => (t._1, t._2.size))
    println(intToInt.mkString(","))

    //println(intToTuples)

    //println(tuples.mkString(","))

  }
}



//TODO  對集合的資料進行篩選,true保留,false過濾
    val ints1: List[Int] = ints.filter(x =>{x%2==1})
    println(ints1.mkString(","))

    //TODO  拉鏈 zip

    val ints2: List[Int] = List(1, 2, 3)
    val ints3: List[Int] = List(3,4, 5, 6,7)
    //形成了元組
    val tuples: List[(Int, Int)] = ints2.zip(ints3)
    println(tuples.mkString(","))//(1,4),(2,5),(3,6)

    //TODO  合并

    val ints4: List[Int] = ints2.union(ints3)
    println(ints4.mkString(","))//1,2,3,3,4,5,6,7
    //TODO 交集
    val ints5: List[Int] = ints2.intersect(ints3)
    println(ints5.mkString(","))

    //TODO 差集(注意要保留哪些集合中的元素)
    val ints6: List[Int] = ints2.diff(ints3)
    println(ints6.mkString(","))//1,2


val ints: List[Int] = List(1, 2, 3, 4)
    //折疊 fold 減少資料
    /*
    fold方法可以傳遞2個部分的引數,第一個部分表示集合之外的資料
    第二部分的引數表示資料進行的邏輯處理
     */
    val i: Int = ints.fold(100)(_ - _)
    println(i)//90
    val i1: Int = ints.foldRight(10)(_ - _)
    println(i1)//8   (1-(2-(3-(4-10))))
  }


//TODO  將2個Map進行合并,相同key做累加,不同的key直接增加
    val stringToInt: mutable.Map[String, Int] = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
    val stringToInt1: mutable.Map[String, Int] = mutable.Map("a" -> 3, "c" -> 2, "d" -> 1)

    val stringToInt2: mutable.Map[String, Int] = stringToInt.foldLeft(stringToInt1)((map, t) => {
      //map集合設定的方式,map(key)=value
      map(t._1) = map.getOrElse(t._1, 0) + t._2
      map
    })
    println(stringToInt2.mkString(","))

//必會

//TODO WordCount
//對集合中的字串統計出現的次數,并且按照出現次數降序排列,取前3
val strings2: List[String] = List("Hello", "Scala", "Python", "World", "Scala", "Kafla", "Dir")


//將相同的單詞放置在一起(分組)
//   (Hello,List("Hello","Hello"))
val tupleToStrings: Map[(String, String), List[String]] = strings2.groupBy(x => (x, x))
//將資料結構進行轉換
val tupleToInt: Map[(String, String), Int] = tupleToStrings.map(t => {
  (t._1, t._2.size)
})
//將資料進行排序
val tuples: List[((String, String), Int)] = tupleToInt.toList.sortWith((left, right) => {
  left._2 > right._2
})
//取排序完成后的前3條資料
val tuples1: List[((String, String), Int)] = tuples.take(3)



scala中的模式匹配

細節和注意事項:

1)如果所有case都不匹配,那么執行case _ 分支,類似于Java中default陳述句

2)如果所有case都不匹配,又沒有寫case _ 分支,那么會拋出MatchError

3)每個case中,不用break陳述句,自動中斷case

4)可以在match中使用其它型別,而不僅僅是字符,可以是運算式
=> 類似于 java swtich 的 :

5)=> 后面的代碼塊到下一個case, 是作為一個整體執行,可以使用{} 括起來,也可以不括,

object Scala_switch_1 {
  def main(args: Array[String]): Unit = {
    val oper='#'
    val n1=20
    val n2=10
    var res = 0
    oper match{
      case '+' => res=n1+n2
      case '-' => res=n1-n2
      case '*' => res=n1*n2
      case '/'=>res=n1/n2
      case _ => println("oper error")
    }
    println("res="+res)

  }
}
for (ch <- "+-3!") {
  var sign = 0
  var digit = 0
  ch match {
    case '+' => sign = 1
    case '-' => sign = -1
    case _ if ch.toString.equals("3") => digit = 3
    case _ => sign = 2
  }
  println(ch + " " + sign + " " + digit)
}
結果:
+ 1 0
- -1 0
3 0 3
! 2 0
val ch = 'V'
ch match {
  case '+' => println("ok~")
  case mychar => println("ok~" + mychar)
  case _ => println ("ok~~")
}

結果:
ok~V

可以匹配物件的任意型別,這樣做避免了使用isInstanceOf和asInstanceOf方法

1)Map[String, Int] 和Map[Int, String]是兩種不同的型別,其它類推,
2)在進行型別匹配時,編譯器會預先檢測是否有可能的匹配,如果沒有則報錯.

匹配陣列:

  1. Array(0) 匹配只有一個元素且為0的陣列,
  2. Array(x,y) 匹配陣列有兩個元素,并將兩個元素賦值為x和y,當然可以依次類推Array(x,y,z) 匹配陣列有3個元素的等等…
  3. Array(0,_*) 匹配陣列以0開始
for(arr <- Array(Array(0),Array(1,0),Array(0,1,0),Array(1,1,0),Array(1,1,0,1))){
  val result = arr match {
    case Array(0) => 0
    case Array(x,y) => x+"="+y
    case Array(0,_*) => "以0開頭的陣列"
    case _ => "什么集合都不是"
  }
  println(arr+"是"+result)
}
case x :: Nil => {
  println("匹配到" + (x::Nil))
  x :: Nil //直接回傳
}



  for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
    val result = list match {
      case 0 :: Nil => "0" 
      case x :: y :: Nil => x + " " + y
      case 0 :: tail => "0 ..."
      case _ => "something else"
    }
    println(result)
  }
for (pair <- Array((0, 1), (1, 0), (2, 1),(1,0,2))) {
  val result = pair match {
    case (0, _) => "0 ..."
    case (y, 0) => y
    case (a,b) => (b,a)
    case _ => "other"
  }
  println(result)
}
結果
0 ...
1
(1,2)
other
object Square {
  def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
  def apply(z: Double): Double = z * z
}

// 模式匹配使用:
val number:Double = 9
number match {
  case Square(n) => println(n)
  case _ => println("nothing matched")
}

物件匹配:

  1. 構建物件時apply會被呼叫 ,比如 val n1 = Square(5)

  2. 當將 Square(n) 寫在 case 后時[case Square(n) => xxx],會默認呼叫unapply 方法(物件提取器)

  3. number 會被 傳遞給def unapply(z: Double) 的 z 形參

  4. 如果回傳的是Some集合,則unapply提取器回傳的結果會回傳給n這個形參

  5. case中物件的unapply方法(提取器)回傳some集合則為匹配成功

  6. 回傳none集合則為匹配失敗

object Names {

  // unapplySeq
  def unapplySeq(str: String): Option[Seq[String]] = {
    if (str.contains(","))
      Some(str.split(","))
    else
      None
  }
}


val namesString = "Alice,Bob"
namesString match {
  case Names(first, second) => {
    println("three people's names")
    // 列印字串
    println(s"$first $second ")
  }
  case _ => println("nothing matched")
}
  1. 當case 后面的物件提取器方法的引數為多個,則會默認呼叫def unapplySeq() 方法

  2. 如果unapplySeq回傳是Some,獲取其中的值,判斷得到的sequence中的元素的個數是否是三個,如果是三個,則把三個元素分別取出,賦值給first,second和third

  3. 其它的規則不變.

樣例類:

  • 樣例類仍然是類
  • 樣例類用case關鍵字進行宣告
  • 樣例類是為模式匹配(物件)而優化的類
  • 構造器中的每一個引數都成為val——除非它被顯式地宣告為var
  • 在樣例類對應的伴生物件中提供apply方法讓你不用new關鍵字就能構造出相應的物件
  • 提供unapply方法讓模式匹配可以作業
  • 自動生成toString、equals、hashCode和copy方法(有點類似模板類,直接給生成,供程式員使用)
  • 除上述外,樣例類和其他類完全一樣,你可以添加方法和欄位,擴展它們
abstract class Amount
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
case object NoAmount extends Amount

for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {
  val result = amt match {
    case Dollar(v) => "$" + v
    case Currency(v, u) => v + " " + u
    case NoAmount => ""
  }
  println(amt + ": " + result)
}


輸出結果:
Dollar(1000.0): $1000.0
Currency(1000.0,RMB): 1000.0 RMB
NoAmount:
val amt = Currency(29.95, "RMB")

val amt1 = amt.copy()
val amt2 = amt.copy(value = 19.95)
val amt3 = amt.copy(unit = "英鎊")

println(amt)
println(amt1)
println(amt2)
println(amt3)

輸出結果:
Currency(29.95,RMB)
Currency(29.95,RMB)
Currency(19.95,RMB)
Currency(29.95,英鎊)


什么是中置運算式?1 + 2,這就是一個中置運算式,如果unapply方法產出一個元組,你可以在case陳述句中使用中置表示法,比如可以匹配一個List序列

var list = List(1, 3, 5, 9)
list match {
  case first :: second :: rest => println(first + "**" + second + "**" + rest)
  case _ => println("匹配不到...")
}

輸出結果:
1**3**List(5, 9)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/275123.html

標籤:其他

上一篇:Kubernetes二進制部署------ETCD

下一篇:ectuShop微信小程式——購物商城專案

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more