Scala重點(基礎、面向對象、高階函數、集合、模式匹配)

1. 基礎語法

1.1. 注釋

和java一樣

 我是單行注釋
/*
我是多行注釋
我是多行注釋
*/
/**
* 我是文檔注釋
* 我是文檔注釋
*/

1.2. 語句

語句可以不以分號結尾

 一條語句獨占一行
println("Hello World!")多條語句在一行
println("Hello World!"); println("Hello Scala!")

1.3. 打印輸出

println("123","123")同時輸出多個字符串

1.4. 常量

val 常量名:常量類型 = 初始值
val max_num:Int = 100

1.5. 變量

var 變量名:變量類型 = 初始值
var minNum:Int = 1Int可以省略,Scala會根據變量值自動匹配類型

官方推薦使用val

更安全

代碼可讀性更高

資源回收更快,方法執行完,val 所定義的常量就會被回收

1.6. 字符串

雙引號、三引號、插值表達式

val|var 變量名 = "字符串"
val|var 變量名 = """
字符串1
字符串2
"""
val|var 變量名 = s"${變量|表達式}字符串"
val a = s"值為:${value}"

1.6.1. 惰性賦值

當有一些變量保存的數據較大時,且這些數據又不需要馬上加載到 JVM 內存中,就可以使用惰性賦值來提高效率

lazy val 變量名 = 表達式
lazy val sql = """
12345
12345
12345
"""
首次被使用該常量才會被加載到內存中。
println(sql)

1.7. 標識符

命名規則

  • 支持大小寫英文字母數字下劃線_美元符$
  • 不能數字開頭;
  • 不能使用關鍵字;
  • 遵循見名知意。
  • 支持"撇撇"。
val `worker.heartbeat.interval` = 3

命名規范

  • 變量和方法:小駝峰,從第二個單詞開始,每個單詞的首字母大寫。例如:maxSize、selectUserById。
  • 類和特征(Trait):大駝峰,每個單詞的首字母都大寫。例如:UserController、WordCount。
  • 包:全部小寫,一般是公司或組織的域名反寫,多級包之間用 . 隔開。例如:com.yjxxt.scala。

1.8. 數據類型

整型是Int不是Integer,Unit相當于java中的void。基本數據類型長度和java一致。

1.9. 類型轉換

1.9.1. 自動類型轉換(小轉大)

val a:Int = 10
val b:Double = a+1.0

1.9.2. 強制類型轉換(大轉小".to類型")

使用".to類型"

val a:Double = 10.2
val b:Int = a.toInt

1.9.3. String類型轉換(toString)

val a:String = "10"
val b:Int = a.toString

1.10. 鍵盤錄入

  • 導包: import scala.io.StdIn
  • 調用方法:通過 StdIn.readXxx() 接收用戶鍵盤錄入的數據
import scala.io.StdIn
val userName = StdIn.readLine()
println(userName)

1.11. 運算符

和java一樣

  • 算術運算符
  • 賦值運算符
  • 關系運算符
  • 邏輯運算符

1.12. 語句塊

用{}括起來的

val result = {println("這是一個語句塊")1+1
}

1.13. 流程控制

和java一樣

  • 順序結構
  • 選擇結構
  • 循環結構

三元表達式

val a = 10 
val b:Boolean = if (a>10) true else false

1.14. 循環

格式

for (i <- 表達式|數組|集合) {語句塊(也叫循環體)
}

守衛

在for語句中添加if語句

for(i 1 to 10 if(i%2==0)) println(i)輸出2、4、6、8、10
to代表【1,10】、Until代表區間【1,10) 

yield生成器

將循環中的參數值返回到一個集合中

val result = for (i <- 1 to 10 if i % 2 == 0) yield i

break和continue

break

 先導包
import scala.util.control.Breaks._當 i == 5 時結束循環
breakable {
for (i <- 1 to 10) {
if (i == 5) break() else println(i)
}
}

continue

 先導包
import scala.util.control.Breaks._當 i == 5 時跳過當次循環,繼續下一次
for (i <- 1 to 10) {
breakable {
if (i == 5) break() else println(i)
}
}

區別在于結束的代碼范圍。

1.15. 方法

在 Scala 中,方法傳參默認是 val 類型,即不可變,這意味著你在方法體內部不能改變傳入的參數。這和 Scala 的設計理念有關,Scala 遵循函數式編程理念,強調方法不應該有副作用。

1.15.1. 語法格式

def 方法名(參數名:參數類型, 參數名:參數類型, ...): [返回值類型] = {語句塊(方法體)
}
def addNum(a:Int, b:Int): Int = {
a + b
}方法中最后一行產生的值就是返回值,可以省略return

1.15.2. 惰性方法

注意:lazy 只支持 val,不支持 var。

使用場景:

數據庫連接,真正使用時才建立連接

提升程序的啟動時間,將某些模塊推遲執行

確保對象中的某些屬性能優先初始化,對其他屬性進行惰性化處理

 定義方法
def addNum(a:Int, b:Int): Int = {
a + b
}惰性加載
lazy val result = addNum(2, 3)首次使用該值時,方法才會執行
println(result)

默認參數

def addNum(a:Int=1,b:Int=2):Int= a+b
val a = addNum
printLn(a) 返回3

帶名參數

def addNum(a:Int=1,b:Int=2):Int= a+b
val a = addNum(b=5)
println(a) 返回6

變長參數

def add(a:Int*):Int={a.sum}
val a = add(1,2,3,4,5)
println(a)返回15

方法調用

后綴調用法

Math.abs(-1)對象.方法(參數)

中綴調用法

Math max (1, 2)對象 方法 參數

花括號調用法

對象.方法{語句塊}
Math.abs{-1}
Math.abs {
println("求絕對值")
-1
}

無括號調用法

方法是無參的

 定義一個無參數的方法
def hello(): Unit = {
println("Hello World!")
}調用方法
hello

1.16. 函數

在Scala函數式編程中,函數是一等公民,主要體現在:

  • 函數可以存儲在變量中
  • 函數可以作為參數
  • 函數可以作為返回值

函數式編程指的是方法的參數列表可以接收函數對象,函數式編程中的函數指的不是程序中的函數(方法),而是數學中的函數即映射關系,例如正弦函數 y=sin(x),x 和 y 的關系。

1.16.1. 定義函數

語法格式

 因為函數是對象,所以函數有類型:(函數參數類型1, 函數參數類型2,...) => 函數返回值類型
val 函數名: (函數參數類型1, 函數參數類型2,...) => 函數返回值類型 = (參數名:參數類型, 參數名:參數類型, ...) => {
函數體
}

注意:

  • 函數的本質就是引用類型,相當于 Java 中 new 出來的實例,所以函數是在堆內存中開辟空間;
  • 函數的定義不需要使用 def 關鍵字,但定義的函數一定要有輸入和返回值,沒有返回值相當于返回的是 Unit;
  • 函數不建議寫 return 關鍵字,會報錯,Scala 會使用函數體的最后一行代碼作為返回值;
  • 因為函數是對象,所以函數有類型,但函數類型可以省略,Scala 編譯期可以自動推斷類型。
val addNum:(a:Int,b:Int)=>(Int) = (a:Int,b:Int)=> a+b
省略函數返回值
val addNum:(a:Int,b:Int)=>{a+b}
val result = addNum(10,20)

1.16.2. 方法和函數的區別

  • 方法是隸屬于類或者對象的,在運行時,它會被加載到 JVM 的方法區中
  • 函數是一個對象,繼承自 FunctionN,函數作為對可以調用一些方法比如有 apply,curried,toString,tupled 這些方法,方法沒有。

1.16.3. 方法轉換成函數

val|var 變量名=方法名_
def addNum(a:Int,b:Int):Int={a+b
}
var c = addNum_
println(c(1,2))

2. 面向對象

2.1. 概念

面向對象的思想是各語言共通的。

2.2. 成員屬性

2.2.1. 初始化成員屬性

? 使用 _ 初始化成員變量時,變量必須聲明數據類型var address: String = _  nullvar phone: Int = _  0

2.3. 成員方法

def eat(): Unit = {println("吃飯")
}
調用方法和java一致

2.4. 訪問權限

Scala 中的權限修飾符只有:private、private[this]、protected、默認這四種。

2.5. 構造器

主構造器

輔助構造器

2.5.1. 主構造器

class 類名(val|var 參數名:類型 = 默認值, val|var 參數名:類型 = 默認值, ...) {語句塊(構造代碼塊)
}
  • 主構造器的參數列表直接定義在類名后面,可以通過主構造器直接定義成員屬性
  • 構造器參數列表可以指定默認值
  • 創建實例時,可以指定參數屬性進行初始化
  • 整個 class 中除了屬性定義和方法定義的代碼都是構造代碼
class Student(var name:String="張三",var age:Int=18) {print("調用主構造器")}
def main(args: Array[String]): Unit = {val zhangsan = new Student();println(zhangsan.name,zhangsan.age)val lisi = new Student("李四",19)println((lisi.name, lisi.age))val wangwu = new Student(name = "wangwu")println(wangwu.name,wangwu.age)
}

2.5.2. 輔助構造器

def this(參數名:類型,參數名:類型){第一行需要調用主構造器或其他構造器輔助構造器代碼
}   
class Teacher {var name:String = _var age:Int = _println("主構造器")def this(name:String,age:Int){this()println("輔助構造器")this.name=namethis.age=age}val zhangsan1 = new Teacher("zhangsan", 18)println(zhangsan1.name,zhangsan1.age)

2.6. 單列對象

相當于java中的靜態類,比如說main方法就是在單列對象object文件中的。

單例對象除了沒有構造器外,可以擁有類的所有特性

object 單列對象名{}
  • 在 object 中定義的成員屬性類似于 Java 的靜態屬性,在內存中都只有一個
  • 在單例對象中,可以直接使用 單列對象名. 的形式調用成員
  • 在單例對象中定義的成員方法類似于 Java 中的靜態方法。
object objectDemo{var str = "這是scala的靜態屬性"def func()=println("這是scala的靜態方法")def main(args: Array[String]): Unit = {println(objectDemo.str)}
}

2.7. 伴生對象

2.7.1. 定義半生對象

在同一個scala文件中,class和object名字一樣時,object稱為伴生對象,class稱為伴生類。他們可以互相訪問彼此的private私有屬性。

object aaa {object A {private val name = "classA"}class A {def getName()=print(A.name)}def main(args: Array[String]): Unit = {new A().getName()}

2.7.2. private[this]權限

該權限下伴生對象和類的屬性不可相互訪問

2.7.3. apply方法

通過伴生對象的apply方法可以在創建對象的時候省去new關鍵字

object 伴生對象名{def apply(參數名:Int,參數名:String...) = new 類(參數1,參數2...)
}
val 對象名 = 伴生對象名(參數1,參數2...)

2.8. 繼承

基本和java一樣

object|class 子 extends 父{}

2.8.1. 方法重寫

override def 父類方法()={} 需要通過override關鍵字重寫

2.8.2. 類型判斷、轉換

 判斷對象是否為指定類型
val trueOrFalse:Boolean = 對象.isInstanceOf[類]將對象轉換為指定類型
val 變量 = 對象.asInstanceOf[類型]

2.9. 抽象類

抽象屬性:沒有初始化值的變量就是抽象屬性

抽象方法:沒有方法體的方法就是抽象方法

abstract class 抽象類名{val |var 抽象屬性名:類型def 方法名(參數:類型,參數:類型):返回值類型
}

2.10. 匿名類

當對象方法僅調用一次的時候

作為方法的參數進行傳遞時

new 類名{重寫父類中所有的抽象內容
}
object Hello {abstract class Hi {def sayHi(str:String) = println(str)}def main(args: Array[String]): Unit = {new Hi{
override def sayHi(str: String): Unit =println(str)}.sayHi("你好呀")}

2.11. 特質

相當于java中的接口

特質可以提高代碼的擴展性和可維護性

類與特質之間是繼承關系,只不過類與類之間只支持單繼承,但是類與特質之間可以多繼承

特質中可以有具體的屬性、抽象屬性、具體的方法以及抽象方法

瘦接口:只有抽象內容

胖接口:有抽象內容和具體內容

trait 特質名稱{具體屬性抽象屬性具體方法	抽象方法
}

繼承特質

class|trait|object A extends 特質B with 特質C
 trait aobject b extends aclass c extends atrait d extends a

2.12. 對象混入

對對象的功能進行臨時增強或者擴展,通過特定的關鍵字,卻可以讓該類的對象具有指定特質中的成員。

val|var 對象名 = new 類 with 特質val user = new User with Logger {override def log(msg: String): Unit = println(msg)
}
trait Logger {定義抽象方法def log(msg: String): Unit定義具體方法def info(msg: String): Unit = log(s"INFO: ${msg}")}類和 Logger 特質之間無任何關系class User {}

2.13. 包

package com.yjxxt.packagespackage com.yjxxt
package packagespackage com.yjxxt {package packages {這里寫類,特質等}
}

3. 高階函數

函數可以存儲在變量中函數可以作為參數函數可以作為返回值

分類

  1. 回調函數(Callback Function)
  2. 偏應用函數(Partial Applied Function)
  3. 柯里化函數(Currying Function)
  4. 閉包函數(Closure Function)

  1. 函數作為參數
  2. 函數作為返回值
  3. 匿名函數(Anonymous Function)
  4. 遞歸函數(Recursive Function)

3.1. 基本使用

函數是引用數據類型,相當于new實例,在堆中開辟空間

函數的定義不需要使用 def 關鍵字,但定義的函數一定要有輸入和返回值,沒有返回值相當于返回的是 Unit;

函數不建議寫 return 關鍵字,Scala 會使用函數體的最后一行代碼作為返回值;

因為函數是對象,所以函數有類型,但函數類型可以省略,Scala 編譯期可以自動推斷類型;

調用函數其實是調用函數里面的 apply 方法來執行邏輯。

def main(args: Array[String]): Unit = {函數最完整寫法val func1:(Int,Int)=>Int = (a:Int,b:Int)=>{a+b}參數部分不寫返回值參數類型如果能夠推斷出來,那么可以省略val func2:(Int,Double)=>Double = (a,b)=>{a+b}如果函數體只有一行代碼,可以省略花括號 {}val func3:(Int,Double)=>Double = (a,b)=>a+b函數類型可以省略,Scala 編譯期可以自動推斷類型因為省略了函數類型,所以參數類型就無法推斷了,這時參數必須聲明類型val func4=(a:Int,b:Int)=>a+b使用 Function1 特質聲明帶一個參數的方法時,需要兩個參數第一個是入參的數據類型,第二個是返回值的數據類型val func5:Int=>Int = new Function[Int,Int]{使用 Function1 特質,必須重寫 apply 接口
override def apply(x: Int): Int = x+1}使用 Function2 特質聲明帶一個參數的方法時,需要三個參數前兩個是入參的數據類型,第三個是返回值的數據類型val func6=new Function2[Int,Double,(Double,Int)] {
override def apply(v1: Int, v2: Double): (Double, Int) = (v1,v2)}使用 Function2 特質,必須重寫 apply 接口val func7 = new ((Int,Double)=>(Double,Int)){
override def apply(v1: Int, v2: Double): (Double, Int) = v1+v2}使用 Function2 特質,必須重寫 apply 接口}

3.2. 至簡原則

優雅

方法和函數不建議寫 return 關鍵字,Scala 會使用函數體的最后一行代碼作為返回值;

方法的返回值類型如果能夠推斷出來,那么可以省略,如果有 return 則不能省略返回值類型,必須指定;

因為函數是對象,所以函數有類型,但函數類型可以省略,Scala 編譯期可以自動推斷類型;

如果方法明確聲明了返回值為 Unit,那么即使方法體中有 return 關鍵字也不起作用;

如果方法的返回值類型為 Unit,可以省略等號 = ;

如果函數的參數類型能夠推斷出來,那么可以省略;

如果方法體或函數體只有一行代碼,可以省略花括號 {} ;

如果方法無參,但是定義時聲明了 () ,調用時小括號 () 可省可不省;

如果方法無參,但是定義時沒有聲明 () ,調用時必須省略小括號 () ;

如果不關心名稱,只關心邏輯處理,那么函數名可以省略。也就是所謂的匿名函數

如果匿名函數只有一個參數,小括號 () 和參數類型都可以省略,沒有參數或參數超過一個的情況下不能省略 () ;

如果參數只出現一次,且方法體或函數體沒有嵌套使用參數,則參數可以用下劃線 _ 來替代。

def main(args: Array[String]): Unit = {方法和函數不建議寫 return 關鍵字,Scala 會使用函數體的最后一行代碼作為返回值;def method1(x:Int,y:Double):Double={x+y}val func1:(Int,Double)=>Double = (a:Int,b:Double)=>{a+b}println(method1(1,2.2),func1(2,2.2))方法的返回值類型如果能夠推斷出來,那么可以省略,如果有 return 則不能省略返回值類型,必須指定;def method2(a:Int,b:Double){a+b}推斷的出def method3(a:Int,b:Double):Double={return a+b}因為函數是對象,所以函數有類型,但函數類型可以省略,Scala 編譯期可以自動推斷類型;val func2=(a:Int,b:Double)=>{a+b}如果方法明確聲明了返回值為 Unit,那么即使方法體中有 return 關鍵字也不起作用;def method4(a:Int,b:Double):Unit={return  a+b}println(method4(1,2.1)) 無返回如果方法的返回值類型為 Unit,可以省略等號 = ;def method5(a:Int,b:Double){a+b}println(method5(2,2.2)) 無返回值可以不寫,不寫的話,即便方法體有內容也不會返回如果函數的參數類型能夠推斷出來,那么可以省略;val func3:(Int,Double)=>Double=(a,b)=>a+bprintln(func3(1,1.2))如果方法體或函數體只有一行代碼,可以省略花括號 {} ;val func4=(a:Int,b:Double)=>a+bdef method6(a:Int,b:Double):Double=a+bprintln(func4(1,1.1),method6(2,2.2))如果方法無參,但是定義時聲明了 () ,調用時小括號 () 可省可不省;def method7()=println("無參有括號")method7()method7如果方法無參,但是定義時沒有聲明 () ,調用時必須省略小括號 () ;def method8 {println("無參無括號")}method8如果不關心名稱,只關心邏輯處理,那么函數名可以省略。也就是所謂的匿名函數;val list =( 1 to 10).toListval list1 = list.map((a) => {
a + 2})如果匿名函數只有一個參數,小括號 () 和參數類型都可以省略,沒有參數或參數超過一個的情況下不能省略 () ;val list2 = list.map(a => a + 2)如果參數只出現一次,且方法體或函數體沒有嵌套使用參數,則參數可以用下劃線 _ 來替代。val list3 = list.map(_ + 2)val i1 = list.reduce((x, y) => x + y)val i = list.reduce(_ + _)}

3.3. 函數作為參數

val str= a =>"*"*a
val list = (1 to 10).toList
極簡寫法相當于list.map(x=>str(x))
val strings:List[String] = list.map(str)
println(strings)

3.4. 函數作為返回值

def func1():(Int,Double)=>Double={
def func2(x:Int,y:Double):Double={x+y
}
func2}println(func1()(2,3.0))func1()(2, 3.0) :調用func1();返回func2拼接上(2,3.0) 就得到f(2, 3.0)。}

4. 集合

Scala 同時支持不可變集合可變集合,因為不可變集合可以安全的并發訪問,所以它也是默認使用的集合類庫。在Scala 中,對于幾乎所有的集合類,都提供了可變和不可變兩個版本,具體如下:

不可變集合:集合內的元素、長度一旦初始化完成就不可再進行更改,任何對集合的改變都將生成一個新的集合。不可變集合都在 scala.collection.immutable 這個包下,使用時無需手動導包。

可變集合:指的是這個集合本身可以動態改變,且可變集合提供了改變集合內元素的方法。可變集合都在scala.collection.mutable 這個包下,使用時需要手動導包。

4.1. 結構樹

藍色為特質(接口),黑色為實現類

4.2. Traversable

4.2.1. 語法格式

創建空的Traversaleval t1 = Traversable.empty[Int]val t2 = Traversable[Int]()val t3 = Nil創建帶元素的Traversable對象val t4 = List(1,2,3).toTraversable List為默認實現類val t5=Array(1,2,3).toTraversableval t6 = Set(1,2,3).toTraversable通過Traversable伴生對象apply方式實現val t7 = Traversable(1,2,3)

4.2.2. 轉置集合transpose

 val t8 = Traversable(Traversable(1,2,3),Traversable(4,5,6),Traversable(7,8,9))val result1 =t8.transposeprintln(result1)List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9))

4.2.3. 拼接集合 Traversable.concat(x,x,x)

  已知有三個 Traversable 集合,分別存儲 (11, 22, 33), (44, 55), (66, 77, 88, 99) 元素通過 concat 方法拼接上述三個集合將拼接后的結果打印到控制臺val t9 = List(11,22,33).toTraversableval t10 = List(44,55).toTraversableval t11 = Traversable(66,77,88,99)val result2 = Traversable.concat(t9,t10,t11)println(result2)List(11, 22, 33, 44, 55, 66, 77, 88, 99)拼接成一個集合

4.2.4. 計算階乘scan(1)(_*_)

val t12 = Traversable(1,2,3,4,5)val result3 = t12.scan(1)(_*_)scan(1)代表起始值為1完整scan(1)((x:Int,y:Int)=>x*y)println(result3)List(1, 1, 2, 6, 24, 120)1*1   1*2  2*3  6*4  24*5從左往右val result4 = t12.scanLeft(1)(_*_)從右往左val result5 = t12.scanRight(1)(_*_)

4.2.5. 獲取元素

head :獲取集合的第一個元素,如果元素不存在,則拋出 NoSuchElementException 異常

last :獲取集合的最后一個元素,如果元素不存在,則拋出 NoSuchElementException 異常

headOption :獲取集合的第一個元素,返回值類型是 Option

lastOption :獲取集合的最后一個元素,返回值類型是 Option

find :查找集合中第一個滿足指定條件的元素

slice :根據起始值,截取集合中的一部分元素(左閉右開)

需求:

定義一個 Traversable 集合,包含 1, 2, 3, 4, 5, 6

分別通過 head、last、headOption、lastOption 獲取集合中的首尾元素

通過 find 方法獲取集合中第一個偶數

通過 slice 方法獲取 3, 4, 5 并將它們放到一個新的 Traversable 集合

val t13 = Traversable(1,2,3,4,5,6)println(t13.head,t13.last,t13.headOption.getOrElse(0),t13.lastOption.getOrElse(0))getOrElse(0)如果不存在就返回0(1,6,Some(1),Some(6))val result6= t13.find(_ % 2 == 0)(x)=>{x%2==0}println(result6)Some(2)val result7=t13.slice(2,5)println(result7)List(3, 4, 5)

4.2.6. 判斷元素是否符合條件forall、exists

def forall(p: (A) => Boolean): Boolean

如果集合中所有元素都滿足指定的條件則返回 true,否則返回 false

def exists(p: (A) => Boolean): Boolean

只要集合中任意一個元素滿足指定的條件就返回 true,否則返回 false

需求:

定義一個 Traversable 集合,包含 1, 2, 3, 4, 5, 6

通過 forall 方法判斷集合中的元素是否都是偶數

通過 exists 方法判斷集合中的元素是否有偶數

  val t14 = Traversable(1,2,3,4,5,6)val result8 = t14.forall(_%2==0)val result9 = t14.exists(_%2==0)println(result8,result9)(false,true)

4.2.7. 聚合操作

count :統計集合中滿足條件的元素個數

sum :獲取集合中所有的元素和

product :獲取集合中所有的元素乘積

max :獲取集合中所有元素的最大值

min :獲取集合中所有元素的最小值

需求:

定義一個 Traversable 集合,包含 1, 2, 3, 4, 5, 6

通過 count 方法統計集合中所有奇數的個數

通過 sum 方法獲取集合中所有元素的和

通過 product 方法獲取集合中所有元素的乘積

通過 max 方法獲取集合中所有元素的最大值

通過 min 方法獲取集合中所有元素的最小值

 val t15 = Traversable(1,2,3,4,5,6)val result10 = t15.count(_%2==1)val result11 = t15.sumval result12 = t15.productval result13 = t15.maxval result14 = t15.minprintln(result10,result11,result12,result13,result14)(3,21,720,6,1)

4.2.8. 類型轉換 toXxx()

toXxx() 方法(toList, toSet, toArray, toSeq 等)。

 需求:

定義一個 Traversable 集合,包含 1, 2, 3, 4, 5, 6

將集合分別轉成數組、列表、集這三種形式,并打印結果

  val t16 = Traversable(1,2,3,4,5,6)val resultArray = t16.toArrayval resultList = t16.toListval resultSet = t16.toSetprintln(resultArray,resultList,resultSet)([I@57855c9a,List(1, 2, 3, 4, 5, 6),Set(5, 1, 6, 2, 3, 4))

4.2.9. 填充元素fil、iterate、range

fill :快速生成指定數量的元素,并放入集合中

iterate :根據指定的條件,生成指定數量的元素,并放入集合中

range :生成某個區間內指定間隔的元素,并放入集合中,左閉右開

需求:

通過 fill 方法,生成一個 Traversable 集合,該集合包含 5 個元素,都是"abc"

通過 fill 方法,生成一個 Traversable 集合,該集合包含 3 個隨機數

通過 fill 方法,生成一個 Traversable 集合,該集合包含 5 個元素,都是 List("abc", "abc") 集合

通過 iterate 方法,生成一個 Traversable 集合,該集合包含 5 個元素,分別為:1, 10, 100, 1000, 10000

通過 range 方法,獲取從數字 1 開始到數字 21 結束,間隔為 5 的所有數據

println(Traversable.fill(5)("abc"))List(abc, abc, abc, abc, abc)println(Traversable.fill(3)(Random.nextInt(100)))一百以內的隨機整數List(62, 71, 37)println(Traversable.fill(5,2)("abc"))5 表示生成的集合中有 5 個集合元素,2 表示每個集合元素的長度為 2List(List(abc, abc), List(abc, abc), List(abc, abc), List(abc, abc), List(abc, abc))println(Traversable.iterate(1,5)(x=>x*10))List(1, 10, 100, 1000, 10000)println(Traversable.range(1,21,5))左閉右開List(1, 6, 11, 16)

4.3. Iterable

4.3.1. 遍歷

  Traversable 提供了兩種遍歷數據的方式:

通過 iterator() 方法實現,迭代訪問元素。這種方式屬于主動迭代,可以通過 hasNext() 檢查是否還有元素,且可以主動的調用 next() 方法獲取元素。即:我們可以自主控制迭代過程。

通過 foreach() 方法實現,遍歷訪問元素。這種方式屬于被動迭代,只需要提供一個函數,并不能控制遍歷的過程。即:迭代過程是由集合本身控制的。

需求:

定義一個 Traversable 集合,包含 1, 2, 3, 4, 5

通過 iterator() 方法遍歷上述列表

通過 foreach() 方法遍歷上述列表

val t17 = Traversable(1,2,3,4,5,6)val iterator: Iterator[Int] = t17.toIteratorwhile(iterator.hasNext){print(iterator.next())}123456println()val result15 = t17.foreach(print)foreach(x=>println(x))123456println()

4.3.2. 分組遍歷grouped(n)

def grouped(size: Int): Iterator[Ierable[A]]

需求:

定義一個 Iterable 集合,存儲 1~13 之間的所有整數

通過 grouped() 方法,對 Iterator 集合按照 5 個元素為一組的形式進行分組,遍歷并打印結果

val t18= (1 to 13).toIterable
val result16 = t18.grouped(5)每組5個result16.foreach(print(_))Vector(1, 2, 3, 4, 5)Vector(6, 7, 8, 9, 10)Vector(11, 12, 13)println()

4.3.3. 按索引生成元組zipWithIndex

 需求:

定義一個 Iterable 集合,存儲 "A", "B", "C", "D", "E"

通過 zipWithIndex() 方法按照 字符串 -> 索引 生成新的集合

將上一步結果通過 map() 方法再按照 索引 -> 字符串 生成新的集合

 val t19 = ('A' to 'E').toIterableval result17 = t19.zipWithIndexprintln(result17)Vector((A,0), (B,1), (C,2), (D,3), (E,4))val result18 = result17.map(x=>x._1->x._2)println(result18)Vector((A,0), (B,1), (C,2), (D,3), (E,4))

4.3.4. 判斷集合是否相同x.sameElements(y)

需求:

定義 Iterable 集合 iter1,包含 "A", "B", "C"

通過 sameElements() 方法,判斷集合 iter1 和 Iterable("A", "B", "C") 是否相同

通過 sameElements() 方法,判斷集合 iter1 和 Iterable("A", "C", "B") 是否相同

定義 Iterable 集合 iter2,包含 "A", "B", "C", "D"

通過 sameElements() 方法,判斷集合 iter1 和 iter2 是否相同

思考:HashSet(1, 5, 2, 3, 4) 和 TreeSet(2, 1, 4, 3, 5) 是否相同?

val t20 = Iterable("A" ,"B", "C")通過 sameElements() 方法,判斷集合 iter1 和 Iterable("A", "B", "C") 是否相同println(t20.sameElements(Iterable("A", "B", "C")))  true
通過 sameElements() 方法,判斷集合 iter1 和 Iterable("A", "B", "C") 是否相同println(t20.sameElements(Iterable("A", "C", "B")))  false
定義 Iterable 集合 iter2,包含 "A", "B", "C", "D"val iter2 = Iterable("A", "B", "C", "D")
通過 sameElements() 方法,判斷集合 iter1 和 iter2 是否相同println(t20.sameElements(iter2))  false
思考:HashSet(1, 5, 2, 3, 4) 和 TreeSet(2, 1, 4, 3, 5) 是否相同?println(mutable.HashSet(1, 5, 2, 3, 4).sameElements(mutable.TreeSet(2, 1, 4, 3, 5)))truefalsefalsetrue

4.3.5. Seq

4.3.6. Set

HashSet:HashSet 是基于 HashMap 實現的,對 HashMap 做了一層簡單的封裝,而且只使用了HashMap 的 Key 來實現各種特性。元素特點唯一、無序。

ListSet:元素特點唯一、有序(元素添加的順序)。

TreeSet:元素特點唯一、排序(按自然順序排序)。

需求:

創建 HashSet 集合,存儲元素 1, 4, 3, 2, 5, 5,然后打印集合

創建 ListSet 集合,存儲 1, 4, 3, 2, 5, 5,然后打印集合

創建 SortedSet 集合,存儲元素 1, 4, 3, 2, 5, 5,然后打印集合

 val hashSet1 = HashSet(1,4,3,2,5,5)val listSet1 = ListSet(1,4,3,2,5,5)val sortSet1 = SortedSet(1,4,3,2,5,5)println(hashSet1,listSet1,sortSet1)(Set(5, 1, 2, 3, 4),ListSet(1, 4, 3, 2, 5),TreeSet(1, 2, 3, 4, 5))

4.3.7. Map

HashMap:元素特點 Key 唯一、無序。

ListMap:元素特點 Key 唯一、有序(元素添加(存儲)的順序)。

TreeMap:元素特點 Key 唯一、排序(按自然順序排序)。

需求:

創建 HashMap 集合,存儲元素 ("A", 1), ("B", 2), ("C", 3), ("C", 3),然后打印集合

創建 ListMap 集合,存儲 ("A", 1), ("C", 3), ("B", 2), ("C", 3),然后打印集合

創建 TreeMap 集合,存儲元素 ("A", 1), ("C", 3), ("B", 2), ("C", 3),然后打印集合

val hashMap1 = HashMap(("A"-> 1), ("B"-> 2), ("C"-> 3), ("C"->3))
val listMap1 = ListMap(("A", 1), ("C", 3), ("B", 2), ("C", 3))
val treeMap1 = TreeMap(("A", 1), ("C", 3), ("B", 2), ("C", 3))
println(hashMap1,listMap1,treeMap1)(Map(A -> 1, B -> 2, C -> 3),ListMap(A -> 1, B -> 2, C -> 3),Map(A -> 1, B -> 2, C -> 3))

4.4. 數組Array

分為可變數組和不可變數組

4.4.1. 不可變數組

數組的長度不允許改變,數組的內容可以改變。

  val|var 數組名 = new Array[元素類型](數組長度)new的數組()寫的是長度val|var 數組名 = Array(元素1, 元素2, 元素3, ...)`非new的數組()寫的是元素

需求:

定義一個長度為 10 的整型數組,設置第 1 個元素為 5,設置第 2 個元素為 10,并打印這兩個元素

定義一個包含 Java,Scala,Python 三個元素的數組,并打印數組長度

  val arr1 = new Array[Int](10)arr1(0)=5arr1(1)=10arr1.foreach(print)println()51000000000

4.4.2. 可變數組

數組的長度和內容都是可變的,可以往數組中添加、刪除元素。

  val|var 變量名 = ArrayBuffer[元素類型]()val|var 變量名 = ArrayBuffer(元素1, 元素2, 元素3, ...)

 需求:

定義一個長度為 0 的整型變長數組

定義一個包含 Hadoop、Hive、Spark 三個元素的變長數組

val arr2 = ArrayBuffer[Int](0)println(arr2)val arr3 = ArrayBuffer[String]("Hadoop","Hive","Spark")arr3.foreach(println)ArrayBuffer(0)HadoopHiveSpark

4.4.3. 增刪改

針對可變數組

+= :添加單個元素

-= :刪除單個元素

++= :追加多個元素到變長數組中

--= :移除變長數組中的多個元素

數組名(索引) = 新值 或者 數組名.update(索引, 新值) :修改元素


val arr4 = ArrayBuffer("Hadoop","Hive","Spark")arr4+="Scala"println(arr4)arr4-="Hadoop"println(arr4)arr4++=Array("Linux","zookeeper")println(arr4)arr4--=Array("Scala","Linux")println(arr4)arr4 ++= ArrayBuffer("Phoenix", "Sqoop")println(arr4)arr4.update(1,"123")println(arr4)arr4(2)="234"ArrayBuffer(Hadoop, Hive, Spark, Scala)ArrayBuffer(Hive, Spark, Scala)ArrayBuffer(Hive, Spark, Scala, Linux, zookeeper)ArrayBuffer(Hive, Spark, zookeeper)ArrayBuffer(Hive, Spark, zookeeper, Phoenix, Sqoop)ArrayBuffer(Hive, 123, zookeeper, Phoenix, Sqoop)

4.4.4. 遍歷數組

val arr5 = Array(1, "2", 3.14, true, null)

遍歷元素

for(i<-arr5){println(i)}遍歷索引for(i<-arr5.indices){println(i)}to 或 untilfor(i <- 0 to arr5.size){println(i)}arr5.foreach(println)

4.4.5. 常用方法

sum() :求和。

max() :求最大。

min() :求最小。

sorted() :排序(正序),返回一個新的數組。倒序可以先排序再反轉。

reverse() :反轉,返回一個新的數組。

var arr6=Array(4,1,3,2,5)println(arr6.sum)println(arr6.max)println(arr6.min)arr6.sorted.foreach(print)printlnarr6.sorted.reverse.foreach(print)println15511234554321

4.5. 元組Tuple

元組的長度和元素都是不可變的。

val|var 元組名 = (元素1, 元素2, 元素3, ...)
val|var 元組名 = 元素1 -> 元素2

注意:格式二只適用于元組中只有兩個元素的情況

需求:

定義一個元組,包含學生的姓名和年齡

分別使用小括號以及箭頭的方式來定義元組

val tuple1 = ("a",1,"123",true,false)println(tuple1)val tuple2 = "一個人"->12println(tuple2)(a,1,123,true,false)(一個人,12)

4.5.1. 訪問元素tuple3._1

元組名._nval tuple3 = ("a",1,"123",true,false)println(tuple3._1,tuple3._5)(a,false)

4.6. 列表List

有序,可重復。

4.6.1. 不可變列表

列表的元素、長度都是不可變的。

val|var 列表名 = List(元素1, 元素2, 元素3, ...)
val|var 列表名 = Nil
val|var 列表名 = 元素1 :: 元素2 :: 元素n :: Nil

需求:

創建一個不可變列表,存放元素

使用 Nil 創建一個不可變的空列表

使用 :: 方法創建列表,包含 -2、-1 兩個元素

val list1 = List(1,2,3,4,5)val list2 = Nilval list3 = -1 :: -1 :: 2 :: Nilprintln(list3)List(-1, -1, 2)

4.6.2. 可變列表

可變列表指的是列表的元素、長度都是可變的。

val|var 列表名 = ListBuffer[數據類型]()
val|var 列表名 = ListBuffer(元素1, 元素2, 元素3, ...

需求:

創建空的整型可變列表

創建一個可變列表,初始化時包含 1, "2", 3.14, true, null 元素

 val list4 = ListBuffer[Any]()val list5 = ListBuffer(1, "2", 3.14, true, null)

4.6.3. 常用方法

列表名(索引) 根據索引(索引從0開始),獲取列表中的指定元素

列表名(索引) = 值 修改元素值

+= 添加單個元素

++= 追加多個元素到可變列表中

-= 刪除單個元素

--= 移除可變列表中的多個元素

toList 將可變列表(ListBuffer)轉換為不可變列表(List)

toArray 將可變列表(ListBuffer)轉換為不可變數組(Array)

toBuffer 將可變列表(ListBuffer)轉換為可變數組(BufferArray)

val list6 = ListBuffer[Int]()

list6+=123

list6.toList+=1 顯然這樣會報錯,因為不可變列表不可添加和修改元素

println(list6)

 需求:

定義一個列表 list1,包含以下元素: 1, "2", 3.14, true, null

使用 isEmpty 方法判斷列表是否為空,并打印結果

再定義一個列表 list2,包含以下元素: "a", "b", "c"

使用 ++ 將兩個列表拼接起來,并打印結果

使用 head 方法,獲取列表的首個元素,并打印結果

使用 tail 方法,獲取列表中除首個元素之外的其他所有元素,并打印結果

使用 reverse 方法,將列表元素反轉,并打印結果

使用 take 方法,獲取列表中的前綴元素,并打印結果

使用 drop 方法,獲取列表中的后綴元素,并打印結果

使用 update 方法,修改指定位置元素,并返回一個修改后的新集合

val list7 = List(1, "2", 3.14, true, null)println(list7.isEmpty)val list8 = List("a", "b", "c")println(list7 ++ list8)println(list7.head)println(list7.tail)println(list7.reverse)println(list7.take(3))前3個數println(list7.drop(4))除了前4個數println(list7.updated(0, "abc"))
falseList(1, 2, 3.14, true, null, a, b, c)1List(2, 3.14, true, null)List(null, true, 3.14, 2, 1)List(1, 2, 3.14)List(null)List(abc, 2, 3.14, true, null)

4.6.4. 扁平化flatten

嵌套列表中的每個元素單獨放到一個新的列表中。

 需求:

定義一個列表,該列表有三個元素,分別為: List("Hello", "World") 、 List("Hello", "Scala") 、

List("Hello", "Spark")

使用 flatten 將這個列表轉換為 List("Hello", "World", "Hello", "Scala", "Hello", "Spark")

val list9 =  List(List("Hello", "World") ,List("Hello", "Scala"), List("Hello", "Spark"))println(list9.flatten)List(Hello, World, Hello, Scala, Hello, Spark)

4.6.5. 拉鏈與拉開zip/unzip

將兩個列表合并成一個列表,列表的元素為元組。無法組成拉鏈的單個元素會被丟棄

將一個列表拆分成兩個列表,兩個列表被元組包含

 需求:

定義列表 names,保存三個學生的姓名,分別為:張三、李四、王五

定義列表 ages,保存學生的年齡,分別為:18、19、20

使用 zip 將列表 names 和 ages 合并成一個列表 list

使用 unzip 將列表 list 拆分成包含兩個列表的元組 tuple

 val names = List("張三","李四","王五")val ages = List(18,19,20)val list= names.zip(ages)println(list)println(list.unzip)List((張三,18), (李四,19), (王五,20))(List(張三, 李四, 王五),List(18, 19, 20))

4.6.6. 轉換字符串toString/mkString

toString :返回 List 中的所有元素的字符串

mkString :可以將元素以指定的分隔符拼接起來并返回,默認沒有分隔符

需求:

定義一個列表,包含元素:1, 2, 3, 4

使用 toString 方法輸出該列表元素

使用 mkString 方法指定分隔符為冒號,并輸出該列表元素

var list10 = (1 to 4).toListprintln(list10.toString())println(list10.mkString(":"))List(1, 2, 3, 4)1:2:3:4

4.6.7. 并集union/交集intersect/差集diff

union并集(合并)操作,且不去重

intersect :表示對兩個列表取交集(相同)

diff :表示對兩個列表取差集(不同)

需求:

定義列表 list1,包含以下元素:1, 2, 3, 4

定義列表 list2,包含以下元素:3, 4, 5, 6

使用 union 獲取 list1 和 list2 的并集

在上一步的基礎上,使用 distinct 去除重復的元素

使用 intersect 獲取 list1 和 list2 的交集

使用 diff 獲取列表 list1 和 list2 的差集

var list11 = List(1,2,3,4)var list12 = List(3,4,6,5)println(list11.union(list12))println(list11.union(list12).distinct)println(list11.intersect(list12))println(list11.diff(list12))List(1, 2, 3, 4, 3, 4, 6, 5)List(1, 2, 3, 4, 6, 5)List(3, 4)List(1, 2)

4.7. 集Set

唯一,自動去重。

4.7.1. 不可變集

元素和長度都不可變

val|var 集名 = Set[類型]()

val|var 集名 = Set(元素1, 元素2, 元素3, ...)

需求:

定義一個空的整型不可變集

定義一個不可變集,保存以下元素:1, 1, 2, 3, 4, 5

var set1 = Set(1,1,2,3,4,5)println(set1)

4.7.2. 可變集

元素和長度都可變

val|var 集名 = mutable.Set[類型]()

val|var 集名 = mutable.Set(元素1, 元素2, 元素3, ...)

需求:

定義一個可變集,包含以下元素:1, 2, 3, 4

添加元素 5 到可變集中

添加元素 6, 7, 8 到可變集中

從可變集中移除元素 3

從可變集中移除元素 3, 5, 7

var set2 = mutable.Set(1, 2, 3, 4)set2+=5println(set2)set2++=List(6,7,8)println(set2)set2-=3println(set2)set2--=Array(3,4,5)println(set2)Set(5, 1, 2, 3, 4)Set(5, 1, 2, 3, 4)Set(5, 1, 6, 2, 7, 3, 8, 4)Set(5, 1, 6, 2, 7, 8, 4)Set(1, 6, 2, 7, 8)set2.update(2,false)刪除set2.update(10,true)添加println(set2)Set(1, 2, 6, 7, 8)Set(1, 6, 10, 7, 8)

4.7.3. 語法格式功能

不可變集返回新的集

4.8. 映射 Map

如果添加相同鍵元素,則后者的值會覆蓋前者的值。

4.8.1. 不可變Map

Map 的元素、長度都是不可變的。

val|var map = Map(鍵1 -> 值1, 鍵2 -> 值2, 鍵3 -> 值3, ...)val|var 集名 = Map((鍵1, 值1), (鍵2, 值2), (鍵3, 值3), ...)

需求:

定義一個 Map,包含以下元素: "張三" -> 18 , "李四" -> 19 , "王五" -> 20

獲取鍵為張三的值

  var map1 = Map("張三"-> 18,"李四"->19,"王五"->20)var map2 = Map(("張三",18),("李四",19),("王五",20))println(map1("張三"))println(map2("李四"))println(map1.getOrElse("zs","不存在"))1819不存在

4.8.2. 可變Map

需求:

定義一個 Map,包含以下元素: "張三" -> 18 , "李四" -> 19 , "王五" -> 20

獲取鍵為張三的值

修改張三的年齡為 28

  var map3 = mutable.Map("張三" -> 18, "李四" -> 19, "王五" -> 20)println(map3("張三"))map3.update("張三", 29)

4.8.3. 遍歷map

for(elem <- map3)println(elem)for((k,v) <-map3)println(k,v)map3.foreach(println)

4.8.4. 常見操作

 需求:

定義一個可變 Map,包含以下元素: "張三" -> 18 , "李四" -> 19 , "王五" -> 20

獲取張三的年齡

獲取所有學生姓名

獲取所有學生年齡

獲取所有學生姓名和年齡

獲取趙六的年齡,如果趙六不存在則返回 -1

新增一個學生: "趙六" -> 21

將李四從 Map 中移除

 var map4 = mutable.Map("張三" -> 18 ,"李四" -> 19 , "王五" -> 20)println(map4.get("張三"))println(map4.keys)println(map4.values)for((k,v)<-map4)println(k,v)println(map4.getOrElse("趙六", -1))println(map4 += "趙六" -> 21)println(map4 -= "李四")Some(18)Set(王五, 張三, 李四)HashMap(20, 18, 19)(王五,20)(張三,18)(李四,19)-1Map(趙六 -> 21, 王五 -> 20, 張三 -> 18, 李四 -> 19)Map(趙六 -> 21, 王五 -> 20, 張三 -> 18)

4.9. range

  val range01: Range.Inclusive = 1 to 5for (i <- range01) println(i)  1 2 3 4 5val range03: Range = 1 to 5 by 2val range03: Range = Range(1, 5, 2)for (i <- range03) println(i)  1 3 5

4.10. 函數式編程

4.10.1. 遍歷foreach


def foreach(f:(A) => Unit): Unit簡寫形式
def foreach(函數)

4.10.2. 去重distinct

val list = List(1, 2, 2, 3, 4, 5, 6)
println(list.distinct)  List(1, 2, 3, 4, 5, 6)

4.10.3. 映射map

 def map[B](f: (A) => B): TraversableOnce[B]簡寫形式def map(函數對象)val result2 = list.map(x => x * 2)println(result2)

4.10.4. 扁平化flatmap

扁平化映射可以理解為先 map,然后再 flatten,它也是將來使用最多的操作,也是必須要掌握的。

def flatMap[B](f: (A) => GenTraversableOnce[B]): TraversableOnce[B]

簡寫形式

def flatMap(f: (A) => 待轉換的集合的處理代碼)

val list = List("hello world", "a new line", "the end")val result3 = list.flatMap(s => s.split("\\s+"))println(s"result3 = ${result3}")根據空格拆分再合并

4.10.5. 過濾filter

def filter(f: (A) => Boolean): TraversableOnce[A]val result1 = list.filter(x => x % 2 == 0)

4.10.6. 排序sorted、sortBy、sortWith

sorted :按默認規則(升序)排序集合

sortBy :按指定屬性排序集合

sortWith :按自定義規則排序集合

val sortby1 = List("01 zookeeper", "02 hadoop", "03 hive", "04 spark")val resSort = sortby1.sortBy(x=>x.split("\\s+")(1))val sortWith1 = List("01 zookeeper", "02 hadoop", "03 hive", "04 spark")val resSort1 = sortWith1.sortWith((x, y) => x > y)println(resSort1)根據字典序排序從左至右List(04 spark, 03 hive, 02 hadoop, 01 zookeeper)

4.10.7. 分組groupBy

  val groupList1 = List("張三" -> "男", "李四" -> "女", "王五" -> "男")val resGroupBy1 = groupList1.groupBy(x=>x._2)println(resGroupBy1)返回Map集合Map(男 -> List((張三,男), (王五,男)), 女 -> List((李四,女)))

4.10.8. 聚合reduce

def reduce[A1 >: A](op: (A1, A1) => A1): A1簡寫形式def reduce(op:(A1, A1) => A1)val listRedu = (1 to 10).toList使用 reduce 計算所有元素的和val resRedu = listRedu.reduce((x, y) => x + y)println(resRedu)55println(listRedu.reduceLeft(_ - _))-53println(listRedu.reduceRight(_ + _))55

4.10.9. 折疊

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1

簡寫形式

def fold(初始值)(op:(A1, A1) => A1)

val listFold = (1 to 10).toListval resFold = listFold.fold(10)((x, y) => x + y)10為起始值println(resFold)65println(list.foldLeft(10)(_ - _))println(list.foldRight(10)(_ - _))

5. 模式匹配

5.1. 語法格式

類似switch只是省去了break

變量 match {case "常量1" => 表達式1case "常量2" => 表達式2case "常量n" => 表達式ncase _ => 表達式n+1
}
  • 先執行第一個 case,看變量值和該 case 對應的常量值是否一致;
  • 如果一致,則執行該 case 對應的表達式;
  • 如果不一致,則執行下一個 case,看變量值和該 case 對應的常量值是否一致;
  • 以此類推,如果所有的 case 都不匹配,則執行 case _ 對應的表達式。

需求:

提示用戶輸入一個單詞并接收

判斷該單詞是否能夠匹配以下單詞,如果能匹配,返回一句話

hadoop:大數據分布式存儲和計算框架

zookeeper:大數據分布式協調服務框架

spark:大數據分布式內存計算框架

其他:未匹配

val str = StdIn.readLine().toLowerCase()
val result1 = str match{case "ABCD" => "這是A"case "B" => "這是B"case _ =>"沒有匹配到"
}
println(result1)

5.2. 匹配類型

對象名 match {

case 變量名1:類型1 => 表達式1

case 變量名2:類型2 => 表達式2

case 變量名n:類型n => 表達式n

case _ => 表達式n+1

}

val a:Any = "Hadoop"
val result2 = a match{case x:Int =>"這是整數"case x:String =>"這是字符串"case _ =>"匹配失敗"
}val result2 = a match {case _: String => "String 類型的數據"case _: Int => "Int 類型的數據"case _: Double => "Double 類型的數據"case _ => "未匹配"}
println(result2)

5.3. 守衛

變量 match {case 變量名 if條件 => 表達式...case _ -> 表達式
}

5.4. 匹配樣例類

對象名 match {case 樣例類型1(屬性1, 屬性2, 屬性n) => 表達式1case 樣例類型2(屬性1, 屬性2, 屬性n) => 表達式2case 樣例類型n(屬性1, 屬性2, 屬性n) => 表達式ncase _ => 表達式n+1
}

case 樣例類后的小括號中的字段個數,要和具體的樣例類的字段個數保持一致。

通過 match 進行模式匹配的時候,要匹配的對象必須聲明為 Any 類型。

創建兩個樣例類 User(姓名, 年齡) 和 Order(編號)

分別定義兩個樣例類的對象,并指定為 Any 類型

使用模式匹配這兩個對象,并分別打印它們的成員

case class User(name:Any,age:Any);
case class Order(id:Int);
val a1:Any = User("張三",19)
val b:Any = Order(1)a1 match{case User(a,b)=>println(a,b)case Order(a)=>println(a)case _ =>println("未匹配")
}
(張三,19)

5.5. 匹配數組

需求:

定義以下數組:

Array(5) :只包含 5 一個元素的數組

Array(x, y) :只包含兩個元素的數組

Array(5, x, y) :以 5 開頭的數組,長度為 3

Array(x, y, 5) :以 5 結尾的數組,長度為 3

Array(5, ...) :以 5 開頭的數組,數量不固定

val arr1 = Array(5)
val arr2 = Array(1,2)
val arr3 = Array(5,6,7)
val arr4 = Array(3,4,5)
val arr5 = Array(5,6,7,8,9)
arr5 match{case Array(x)=>println(x)case Array(x,y)=>println(x,y)case Array(5,x,y)=>println(5,x,y)case Array(x,y,5)=>println(x,y,5)case Array(5,_*) =>println("以5開頭的很長的數組")case _ => println("未匹配")
}

5.6. 匹配列表

需求:

定義以下列表:

List(5) :只包含 5 一個元素的列表

List(x, y) :只包含兩個元素的列表

List(5, x, y) :以 5 開頭的列表,長度為 3

List(x, y, 5) :以 5 結尾的列表,長度為 3

List(5, ...) :以 5 開頭的列表,數量不固定

和上面一樣

5.7. 匹配集

和列表數組一樣的

5.8. 匹配映射

由于 Map 中的元素就是一個一個的二元組,所以在遍歷時,可以使用元組匹配。

定義val map1 = Map("A" -> 1, "B" -> 2, "C" -> 3)

使用匹配模式,匹配上述 Map

val map1 = Map("A" -> 1, "B" -> 2, "C" -> 3)
for((k,v)<-map1){println(k,v)
}
(A,1)
(B,2)
(C,3)
for(("A",x)<-map1){println("A",x)
}
(A,1)
for((k,v)<-map1 if v%2==0){println(k,v)
}
(B,2)

5.9. 變量聲明的匹配

生成包含 0-10 數字的數組,使用模式匹配分別獲取第二個、第三個、第四個元素

生成包含 0-10 數字的列表,使用模式匹配分別獲取第一個、第二個元素

val arr6 = (0 to 10).toArray
val list1 = (0 to 10).toList
val Array(_,x,y,z,_*) = arr6
//將值取到x,y,z當中
val List(a2,b1,c,_*) = list1
//將值取到a,b當中
println(x,y,z,a2,b1)
(1,2,3,0,1)

5.10. 匹配Option

5.11. 偏函數

val pf2: PartialFunction[Int, String] = {//參數值和函數返回值case 1 => "One"case 2 => "Two"case 3 => "Three"
}
println(pf2.isDefinedAt(1), pf2.isDefinedAt(4))
//(true,false)

5.12. 結合函數使用

5.12.1. collect

在 Scala 中,我們還可以通過 collect() 方法實現偏函數結合集合來使用,從集合中篩選指定的數據。

def collect[B](pf: PartialFunction[A, B]): Traversable[B]

 需求:

已知一個 List 列表,存儲元素為:1, 2, 3, 4, 5, 6, 7, 8, 9, 10

通過 collect 函數篩選出集合中所有的偶數

 val list10 = (1 to 10).toList
val pf:PartialFunction[Int,Int]={case x if x%2 == 0=>x
}
val result10 = list10.collect(pf);
println(result10)
List(2, 4, 6, 8, 10)
//合并版
val result11 = list10.collect{case x if x%2==0=>x
}
println(result11)

5.12.2. map

需求:

定義一個列表,包含 1-10 的數字

請將 1-3 的數字都轉換為 [1-3]

請將 4-8 的數字都轉換為 [4-8]

將其他的數字轉換為 (8-*]

var list12 = (1 to 10).toList
val result12 = list12.map{case x if x >=1 && x<=3 =>"[1-3]"case x if x >=4 && x<=8 =>"[4-5]"case _ =>"(8-*]"
}
println(result12)
val list = List("張三" -> 18, "李四" -> 19, ("tuple1", "tuple2", "tuple3"),
(1 to 5).toList, 5, "Scala")
list.foreach{case (k,v)=>println(k,v)case (x,y,z) =>println(x,y,z)case x:List[Int] =>println(x)case x:Int=>println(x)case x:String =>println(x)
}
// (張三,18)
// (李四,19)
// (tuple1,tuple2,tuple3)
// List(1, 2, 3, 4, 5)
// 5
// Scala

5.12.3. foreach

需求:定義列表 List(("張三", 18), ("李四", 19), 5, "Scala", (1 to 5).toList) ,根據不同的元素類型

做出不同的處理。

val list20 = List("張三" -> 18, "李四" -> 19, ("tuple1", "tuple2", "tuple3"),(1 to 5).toList, 5, "Scala")list20.foreach{case (k,v) =>println(k,v)case (x,y,z) =>println(x,y,z)case x:List[Int] =>println(x)case x:Int =>println(x)case x:String =>println(x)case _ =>println("匹配失敗")}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93210.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93210.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93210.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

明遠智睿T113-i核心板:工業設備制造領域的革新利器

在工業設備制造這片充滿挑戰與機遇的領域&#xff0c;技術革新如同一股洶涌浪潮&#xff0c;不斷重塑著市場競爭的格局。隨著技術持續進步&#xff0c;市場競爭愈發激烈&#xff0c;制造商們面臨著如何在保證產品卓越性能的同時&#xff0c;有效控制成本這一關鍵難題。在此背景…

122-基于Flask的校園霸凌數據可視化分析系統

校園霸凌數據可視化分析系統 - 基于Flask的全棧數據分析平臺 本文詳細介紹了一個基于Flask框架開發的校園霸凌數據可視化分析系統&#xff0c;從技術架構到功能實現&#xff0c;為數據分析項目開發提供參考。 &#x1f4cb; 目錄 項目概述技術架構核心功能代碼結構技術棧詳解核…

Docker 網絡設置方式詳解

Docker 網絡是容器通信的核心基礎&#xff0c;它允許容器之間、容器與主機之間以及容器與外部網絡之間進行數據交互。Docker 提供了多種網絡驅動類型&#xff0c;適用于不同場景&#xff0c;下面詳細介紹 Docker 網絡的設置方式。一、Docker 網絡的基本概念 Docker 網絡通過驅動…

export default和export function的作用及export的含義

在 JavaScript 中&#xff0c;export 是一個關鍵字&#xff0c;用于將模塊中的變量、函數、類等導出&#xff0c;以便其他模塊可以導入和使用。export default 和 export&#xff08;非默認導出&#xff09;是兩種不同的導出方式&#xff0c;它們在使用場景和語義上有明顯的區別…

免費 ollama 可用地址共享 內含免費 deepseek,gpt,bge,llama,Qwen,embed 大模型等

ollama 共享 介紹 集ollama地址的批量添加&#xff0c;批量校驗&#xff0c;批量獲取 &#xff0c;api接口調用于一體 演示地址&#xff1a;ollama格式化工具 開源地址&#xff1a;https://gitee.com/web/ollama-share 使用說明 index.php 通過提交table 批量提交ollama地…

Android Audio實戰——獲取活躍音頻類型(十五)

在 Android Audio 開發中,很多場景需要獲取當前正在播放的音頻類型,而在音頻管理器 AudioManager 中并沒有發現類似的接口,這一篇文章就來看一下實現獲取活躍音頻類型的方式。 一、音頻類型獲取 對于獲取當前活躍音頻流類型,在《硬按鍵調節音量》中是通過 getActiveStream…

Verilog功能模塊--SPI主機和從機(02)--SPI主機設計思路與代碼解析

前言 上一篇文章介紹了SPI的四種工作模式及其時序特性&#xff0c;相信各位同學已經掌握了SPI通信的核心原理。 本文用純Verilog設計了功能完整的4線SPI主機&#xff0c;并詳細說明了模塊編碼思路和使用注意事項&#xff0c;最后分享了源碼。 一、模塊功能 本Verilog功能模塊—…

Decoder模型 向量模長表示什么

Decoder模型 向量模長表示什么 詞和其他詞的關系的強弱和關聯程度;生僻詞模長小 從實驗結果來看,Qwen2-7B-Instruct的向量模長規律與之前的預期(“模長與語義豐富度、確定性正相關”)完全相反,這反映了Decoder-only模型(尤其是指令微調模型)的表征特性與Encoder-only模…

STL容器及其算法

C 標準庫容器詳解&#xff1a;特性、用法與場景選型容器是 C 標準庫&#xff08;STL&#xff09;的核心組件&#xff0c;用于存儲和管理數據。不同容器因底層實現不同&#xff0c;在性能、功能和適用場景上差異顯著。本文系統梳理vector、list、set、map等常用容器&#xff0c;…

MySQL ZIP安裝教程:從解壓到啟動

金金金上線&#xff01; 話不多&#xff0c;只講你能聽懂的前端知識 前言 我這里不能下載安裝程序的mysql&#xff0c;由于電腦安全限制&#xff0c;安裝時會彈出需要管理員賬號密碼權限&#xff0c;此路行不通&#xff0c;所以琢磨著免安裝版本怎么個流程&#xff0c;好&#…

p2p打洞

p2p網絡穿透庫,它的C++版本目前只支持linux,不支持win,它最新版本的穿透用的tcp,老版本支持tcp/udp: https://libp2p.io/ P2P-udp的穿透教程: https://edu.51cto.com/lesson/731596.html 目前打洞機制最好的庫是webrtc,其次是libnice,它是輕量級的專門打洞的庫。 libni…

『“無恙心寬”,梗痛不常』——愛上古中醫(12)(健康生活是coder抒寫優質代碼的前提條件——《黃帝內經》伴讀學習紀要)

養心護心氣血通&#xff0c;無痛無梗全身松。 筆記模板由python腳本于2025-08-10 15:54:46創建&#xff0c;本篇筆記適合至少通曉一門語言&#xff0c;熟悉基本編程范式的coder翻閱。 學習的細節是歡悅的歷程 博客的核心價值&#xff1a;在于輸出思考與經驗&#xff0c;而不僅僅…

Spark 運行流程核心組件(一)作業提交

1、Job啟動流程1、Client觸發 SparkContext 初始化 2、SparkContext 向 Master 注冊應用 3、Master 調度 Worker 啟動 Executor 4、Worker 進程啟動 Executor 5、DAGScheduler 將作業分解為 Stage&#xff1a; 6、TaskScheduler 分配 Task 到 Executor 2、核心組件組件職責Spar…

MySQL 臨時表與復制表

一、MySQL 臨時表臨時表是會話級別的臨時數據載體&#xff0c;其設計初衷是為了滿足短期數據處理需求&#xff0c;以下從技術細節展開說明。&#xff08;一&#xff09;核心特性拓展1.生命周期與會話綁定會話結束的判定&#xff1a;包括正常斷開連接&#xff08;exit/quit&…

從配置到調試:WinCC與S7-1200/200SMT無線Modbus TCP通訊方案

測試設備與參數l 西門子PLC型號&#xff1a;S7-1200 1臺l 西門子PLC型號&#xff1a;S7-200Smart 1臺l 上位機&#xff1a;WinCC7.4 1臺l 無線通訊終端——DTD418MB 3塊l 主從關系&#xff1a;1主2從l 通訊接口&#xff1a;RJ45接口l 供電&#xff1a;12-24VDCl 通訊協議&a…

Android沉浸式全屏顯示與隱藏導航欄的實現

1. 總體流程以下是實現沉浸式全屏顯示和隱藏導航欄的流程&#xff1a;步驟描述步驟1創建一個新的Android項目步驟2在布局文件中定義需要展示的界面步驟3在Activity中設置沉浸式全屏顯示步驟4處理系統UI的顯示與隱藏步驟5運行應用并測試效果2. 詳細步驟步驟1&#xff1a;創建一個…

EN 62368消費電子、信息技術設備和辦公設備安全要求標準

EN 62368認證標準是一項全球性的電子產品安全標準&#xff0c;用于評估和認證消費電子、信息技術設備和辦公設備的安全性。該標準由國際電工委員會(IEC)制定&#xff0c;取代了傳統的EN60065和EN 60950兩個標準&#xff0c;成為國際電子產品安全領域的新指導。IEC /EN 62368-1是…

【unity實戰】使用Splines+DOTween制作彎曲手牌和抽牌動畫效果

最終效果 文章目錄最終效果前言實戰1、Splines的使用2、繪制樣條線3、DOTween安裝和使用4、基于樣條曲線&#xff08;Spline&#xff09;的手牌管理系統4.1 代碼實現4.2 解釋&#xff1a;&#xff08;1&#xff09;計算第一張卡牌的位置&#xff08;居中排列&#xff09;&#…

Flask模板注入梳理

從模板開始介紹&#xff1a;Flask中有許多不同功能的模板&#xff0c;他們之間是相互隔離的地帶&#xff0c;可供引入和使用。Flask中的模塊&#xff1a;flask 主模塊&#xff1a;包含框架的核心類和函數&#xff0c;如 Flask&#xff08;應用實例&#xff09;、request&#x…

企業級的即時通訊平臺怎么保護敏感行業通訊安全?

聊天記錄存在第三方服務器、敏感文件被誤發至外部群組、離職員工仍能查看歷史消息.對于金融、醫療、政務等對數據安全高度敏感的行業而言&#xff0c;“溝通效率與”信息安全”的矛盾&#xff0c;從未像今天這樣尖銳。企業即時通訊怎么保護敏感行業通訊安全&#xff1f;這個問題…