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中將方法的回傳值型別放置在方法宣告的后面使用冒號連接
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的其他方法
| 序號 | 方法 | 描述 |
|---|---|---|
| 1 | def +(elem: A): Set[A] | 為集合添加新元素,并創建一個新的集合,除非元素已存在 |
| 2 | def -(elem: A): Set[A] | 移除集合中的元素,并創建一個新的集合 |
| 3 | def contains(elem: A): Boolean | 如果元素在集合中存在,回傳 true,否則回傳 false, |
| 4 | def &(that: Set[A]): Set[A] | 回傳兩個集合的交集 |
| 5 | def &~(that: Set[A]): Set[A] | 回傳兩個集合的差集 |
| 6 | def ++(elems: A): Set[A] | 合并兩個集合 |
| 7 | def drop(n: Int): Set[A]] | 回傳丟棄前n個元素新集合 |
| 8 | def dropRight(n: Int): Set[A] | 回傳丟棄最后n個元素新集合 |
| 9 | def dropWhile(p: (A) => Boolean): Set[A] | 從左向右丟棄元素,直到條件p不成立 |
| 10 | def max: A //演示下 | 查找最大元素 |
| 11 | def min: A //演示下 | 查找最小元素 |
| 12 | def 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), 請撰寫程式實作.
1:
import 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(","))
}
}
2:
val 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)在進行型別匹配時,編譯器會預先檢測是否有可能的匹配,如果沒有則報錯.
匹配陣列:
- Array(0) 匹配只有一個元素且為0的陣列,
- Array(x,y) 匹配陣列有兩個元素,并將兩個元素賦值為x和y,當然可以依次類推Array(x,y,z) 匹配陣列有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")
}
物件匹配:
-
構建物件時apply會被呼叫 ,比如 val n1 = Square(5)
-
當將 Square(n) 寫在 case 后時[case Square(n) => xxx],會默認呼叫unapply 方法(物件提取器)
-
number 會被 傳遞給def unapply(z: Double) 的 z 形參
-
如果回傳的是Some集合,則unapply提取器回傳的結果會回傳給n這個形參
-
case中物件的unapply方法(提取器)回傳some集合則為匹配成功
-
回傳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")
}
-
當case 后面的物件提取器方法的引數為多個,則會默認呼叫def unapplySeq() 方法
-
如果unapplySeq回傳是Some,獲取其中的值,判斷得到的sequence中的元素的個數是否是三個,如果是三個,則把三個元素分別取出,賦值給first,second和third
-
其它的規則不變.
樣例類:
- 樣例類仍然是類
- 樣例類用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
標籤:其他
