文章目录
一,Scala模式匹配介绍
模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。它是Java中的switch
语句的升级版,同样可以用于替代一系列的if/else
语句。
模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支,类似于 Java 中 default 语句。
package com.cw.chapter11
import scala.collection.GenTraversableOnce
object Scala01_Match {
def main(args: Array[String]): Unit = {
// 模式匹配,类似于Java的switch语法
/*
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,
当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,
如果匹配不成功,继续执行下一个分支进行判断。
如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句。
*/
// TODO match的细节和注意事项
// 1) 如果所有case都不匹配,那么执行case _ 分支,类似于Java中default语句
// 2) 如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError
// 3) 每个case中,不用break语句,自动中断case
// 4) 可以在match中使用其它类型,而不仅仅是字符,可以是表达式
// 5) => 类似于 java swtich 的 :
// 6) => 后面的代码块到下一个case, 是作为一个整体执行,可以使用{} 括起来,也可以不括。
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)
}
}
二,模式守卫
如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫,也就是在模式后面加上if <boolean expression>
。
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
case Email(sender, _, _) if importantPeopleInfo.contains(sender) =>
"You got an email from special someone!"
case SMS(number, _) if importantPeopleInfo.contains(number) =>
"You got an SMS from special someone!"
case other =>
showNotification(other) // nothing special, delegate to our original showNotification function
}
}
val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")
val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")
println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))
在case Email(sender, _, _) if importantPeopleInfo.contains(sender)
中,除了要求notification
是Email
类型外,还需要sender
在重要人物列表importantPeopleInfo
中,才会匹配到该模式。
案例2
object TestMatchGuard {
def main(args: Array[String]): Unit = {
def abs(x: Int) = x match {
case i: Int if i >= 0 => i
case j: Int if j < 0 => -j
case _ => "type illegal"
}
println(abs(-5))
}
}
案例2
val a = StdIn.readInt()
a match {
case _ if a >= 0 && a <= 3 => println("[0-3]")
case _ if a >= 4 && a <= 8 => println("[3-8]")
case _ => println("未匹配")
}
二,典型的模式匹配场景
2.1 匹配字符串
Scala 中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
object Test01 {
def main(args: Array[String]): Unit = {
val arr=Array("aa","bb","cc")
//随机获取数组的任意元素
val index=Random.nextInt(3)
val value=arr(index)
//模式匹配
value match{
case "aa" => println("0")
case "bb" => println("1")
case "cc" => println("2")
case _ => println("null") //表示所有的都没有匹配到执行这里
}
}
}
案例2
package com.cw.chapter11
object Scala03_Match1 {
def main(args: Array[String]): Unit = {
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)
}
// 如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量
val ch = 'V'
ch match {
case '+' => println("ok~")
case mychar => println("ok~" + mychar)
case _ => println("ok~~")
}
}
}
案例3
object TestMatchVal {
def main(args: Array[String]): Unit = {
println(describe(6))
}
def describe(x: Any) = x match {
case 5 => "Int five"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
}
}
2.2 匹配类型
需要进行类型判断时,可以使用isInstanceOf[T]
和asInstanceOf[T]
,也可使
用模式匹配实现同样的功能。
object Test01 {
def main(args: Array[String]): Unit = {
val arr=Array("aa",18,4.4,true)
//随机获取数组的任意元素
val index=Random.nextInt(arr.length)
val value=arr(index)
//模式匹配
value match{
case x:Int if(x>3) => println("Int")
case y:String => println("String")
case z:Double => println("Double")
case flag:Boolean => println("Boolean")
case _ => println("null") //表示所有的都没有匹配到执行这里
}
}
}
案例二
package com.cw.chapter11
object Scala04_Match2 {
def main(args: Array[String]): Unit = {
// 可以匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf方法
// 类型匹配, obj 可能有如下的类型
val a = 7
val obj = if (a == 1) 1
else if (a == 2) "2"
else if (a == 3) BigInt(3)
else if (a == 4) Map("aa" -> 1) // Map[String, Int]
else if (a == 5) Map(1 -> "aa") // Map[Int, String]
else if (a == 6) Array(1, 2, 3) // Array[Int]
else if (a == 7) Array("aa", 1) // Array[Any]
else if (a == 8) Array("aa") // Array[String]
// 类型匹配时,泛型是不起作用的,Array[Int]并不是代表泛型,只是表示数据类型的规约
val result = obj match {
case a: Int => a
case b: Map[String, Int] => "对象是一个字符串-数字的Map集合"
case c: Map[Int, String] => "对象是一个数字-字符串的Map集合"
case d: Array[String] => "对象是一个字符串数组" // 底层转为 new String[];
case e: Array[Int] => "对象是一个数字数组" // 底层转成new int[];
case f: BigInt => Int.MaxValue
case g: Array[Any] => "Any"
case _ => "啥也不是"
}
println(result)
// 在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错.
}
}
案例3
abstract class Device
case class Phone(model: String) extends Device {
def screenOff = "Turning screen off"
}
case class Computer(model: String) extends Device {
def screenSaverOn = "Turning screen saver on..."
}
def goIdle(device: Device) = device match {
case p: Phone => p.screenOff
case c: Computer => c.screenSaverOn
}
当不同类型对象需要调用不同方法时,仅匹配类型的模式非常有用,如上代码中goIdle
函数对不同类型的Device
有着不同的表现。一般使用类型的首字母作为case
的标识符,例如上述代码中的p和c,这是一种惯例。
2.3 匹配数组、元组、集合
scala 模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素
为 0 的数组。
object Test01 {
def main(args: Array[String]): Unit = {
//匹配数组
val arr3=Array(0,1,2,3,4,5)
arr3 match{
case Array(0,x,y) => println(x+"--"+y) //匹配以0开头,后面两个元素的数组
case Array(0) => println("only 0") //匹配只有一个元素的数组
case Array(0,_*) => println("many") //匹配以0开头的数组,_表示任意元素,*表示一到多个元素
}
//匹配序列
val lst1=List(3,1,-1)
lst1 match{
case 0::Nil => println("only 0") //匹配只有一个元素0的序列
case x::y::Nil =>println(x+"--"+y) //匹配有两个元素的序列
case 0::tail => println("0 is head ") //匹配以0开头的序列
case _ => println("nothing ")
}
//匹配元组
val tuple=(2,3,4)
tuple match {
case (1,x,y) => println("1 is head ") //匹配以1开头的 3个元素的tuple
case (_,x,y) => println("many") //匹配以任意开头的 3个元素的tuple
case _ => println("nothing ")
}
}
}
运行结果
many
nothing
many
Spark源码中模式匹配场景
package org.apache.spark.deploy.yarn
import scala.collection.mutable.ArrayBuffer
// TODO: Add code and support for ensuring that yarn resource 'tasks' are location aware !
private[spark] class ClientArguments(args: Array[String]) {
var userJar: String = null
var userClass: String = null
var primaryPyFile: String = null
var primaryRFile: String = null
var userArgs: ArrayBuffer[String] = new ArrayBuffer[String]()
parseArgs(args.toList)
private def parseArgs(inputArgs: List[String]): Unit = {
var args = inputArgs
while (!args.isEmpty) {
args match {
// 匹配以 "--jar" 开头,后面至少一个值 的参数
// tail就是其他的意思,这种结构连到一起就是匹配上的,
// 如果args= "--jar","jars1"则会被匹配上,value则取值就是jars1
case ("--jar") :: value :: tail =>
userJar = value
args = tail //
case ("--class") :: value :: tail =>
userClass = value
args = tail
case ("--primary-py-file") :: value :: tail =>
primaryPyFile = value
args = tail
case ("--primary-r-file") :: value :: tail =>
primaryRFile = value
args = tail
case ("--arg") :: value :: tail =>
userArgs += value
args = tail
case Nil =>
case _ =>
throw new IllegalArgumentException(getUsageMessage(args))
}
}
if (primaryPyFile != null && primaryRFile != null) {
throw new IllegalArgumentException("Cannot have primary-py-file and primary-r-file" +
" at the same time")
}
}
}
MasterArguments参数解析的时候也有这么一段:
private def parse(args: List[String]): Unit = args match {
// 匹配以 "--ip"或者"-i" 开头,后面至少一个值 的参数
case ("--ip" | "-i") :: value :: tail =>
Utils.checkHost(value)
host = value
parse(tail)
case ("--host" | "-h") :: value :: tail =>
Utils.checkHost(value)
host = value
parse(tail)
case ("--port" | "-p") :: IntParam(value) :: tail =>
port = value
parse(tail)
case "--webui-port" :: IntParam(value) :: tail =>
webUiPort = value
parse(tail)
case ("--properties-file") :: value :: tail =>
propertiesFile = value
parse(tail)
case ("--help") :: tail =>
printUsageAndExit(0)
case Nil => // No-op
case _ =>
printUsageAndExit(1)
}
2.4 匹配对象
2.4.1 apply和unapply方法介绍
提取器对象是一个包含有unapply
方法的单例对象。apply
方法就像一个构造器,接受参数然后创建一个实例对象,反之unapply
方法接受一个实例对象然后返回最初创建它所用的参数。提取器常用在模式匹配和偏函数中。
import scala.util.Random
object CustomerID {
def apply(name: String) = s"$name--${Random.nextLong}"
def unapply(customerID: String): Option[String] = {
val stringArray: Array[String] = customerID.split("--")
if (stringArray.tail.nonEmpty) Some(stringArray.head) else None
}
}
val customer1ID = CustomerID("Sukyoung") // Sukyoung--23098234908
customer1ID match {
case CustomerID(name) => println(name) // prints Sukyoung
case _ => println("Could not extract a CustomerID")
}
这里apply
方法用name
创建一个CustomerID
字符串。而unapply
方法正好相反,它返回name
。当我们调用CustomerID("Sukyoung")
,其实是调用了CustomerID.apply("Sukyoung")
的简化语法。当我们调用case CustomerID(name) => println(name)
,就是在调用提取器方法。
因为变量定义可以使用模式引入变量,提取器可以用来初始化这个变量,使用unapply
方法来生成值。
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
上面的代码等价于val name = CustomerID.unapply(customer2ID).get
。
val CustomerID(name2) = "--asdfasdfasdf"
如果没有匹配的值,会抛出scala.MatchError
:
val CustomerID(name3) = "-asdfasdfasdf"
unapply 方法的返回值应当符合下面的某一条:
- 如果只是用来判断真假,可以返回一个 Boolean 类型的值。例如 case even()。
- 如果只是用来提取单个 T 类型的值,可以返回 Option[T]。
- 如果你想要提取多个值,类型分别为 T1,…,Tn,可以把它们放在一个可选的元组中 Option[(T1,…,Tn)]。
有时,要提取的值的数量不是固定的,因此我们想根据输入来返回随机数量的值。这种情况下,你可以用unapplySeq
方法来定义提取器,此方法返回Option[Seq[T]]
。常见的例子有,用case List(x, y, z) =>
来解构一个列表 List,以及用一个正则表达式 Regex 来分解一个字符串 String,例如 case r(name, remainingFields @ _*) =>
。
2.4.2 对象匹配细节介绍
package com.cw
// TODO 对象匹配
// 对象匹配,什么才算是匹配呢?规则如下:
// 1) case中对象的unapply方法(对象提取器)返回Some集合则为匹配成功
// 2) 返回none集合则为匹配失败
// 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这个形参
object Square {
// 当对对象进行匹配时,会自动调用unapply方法
def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
//def unapply(z: Double): Option[Double] = None
// 构建对象时apply会被调用,比如 val n1 = Square(5)
def apply(z: Double): Double = z * z
}
/**
* @author 陈小哥cw
* @date 2021/3/31 10:07
*/
object Test {
def main(args: Array[String]): Unit = {
val result = Square(6) // 36
println(result)
// 模式匹配使用:
val number: Double = 36.0
number match {
case Square(n) => println(n) // 当对对象进行匹配时,会自动调用unapply方法
case _ => println("nothing matched")// 当unapply返回None时,会匹配这里
}
}
}
运行结果
36.0
6.0
小结
val result = Square(6)
,该语句在执行时,实际调用的是Square
伴生对象中的
apply
方法,因此不用new
关键字就能构造出相应的对象- 若只提取对象的一个属性,则提取器为
unapply(obj:Obj):Option[T]
- 若提取对象的多个属性,则提取器为
unapply(obj:Obj):Option[(T1,T2,T3…)]
- 若提取对象的可变个属性,则提取器为
unapplySeq(obj:Obj):Option[Seq[T]]
- case 中对象的
unapply
方法(提取器)返回Some
,且所有属性均一致,才算匹配成功,
属性不一致,或返回None
,则匹配失败
2.5 匹配异常
package com.cw
import java.io.IOException
/**
* @author 陈小哥cw
* @date 2021/3/31 10:07
*/
object Test {
def main(args: Array[String]): Unit = {
try {
println(3 / 0) // ArithmeticException
} catch {
case e: IOException => println("IOException")
case e: ArithmeticException => println("算术运算异常[ArithmeticException]")
case e: Exception => println("Exception")
} finally {
println("程序结束!")
}
println("---------------------------")
var arr = List(1, 2, 3)
try {
println(arr(4)) // IndexOutOfBoundsException
} catch {
case e: IOException => println("IOException")
case e: ArithmeticException => println("算术运算异常[ArithmeticException]")
case e: Exception => println("Exception")
} finally {
println("程序结束!")
}
}
}
运行结果
算术运算异常[ArithmeticException]
程序结束!
---------------------------
Exception
程序结束!
三,变量声明和for表达式中的模式匹配
package com.cw.chapter11
object Scala06_Match4 {
def main(args: Array[String]): Unit = {
// TODO 变量声明中的模式匹配
// match中每一个case都可以单独提取出来,意思是一样的.
val (x, y) = (1, 2)
println(x + " = " + y)
val (username, age, email) = ("zhangsan", 20, "133@163.com")
println(username + " = " + age + " = " + email)
val (q, r) = BigInt(10) /% 3 // 包含了2个连续的运算符,可以同时获取结果和余数
println("q = " + q) // 结果
println("r = " + r) // 余数
val arr = Array(1, 7, 2, 9)
val Array(first, second, _*) = arr
println(first, second)
// TODO for表达式中的模式匹配
val list = List(("a", 1), ("b", 2), ("c", 3))
for ((k, v) <- list) {
println(k + " = " + v)
}
val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
for ((k, v) <- map) {
println(k + " -> " + v)
}
for ((k, 0) <- map) {
println(k + " --> " + 0)
}
for ((k, v) <- map if v == 0) {
println(k + " ---> " + v)
}
}
}
四,样例类
在scala中样例类是一种特殊的类,可用于模式匹配。
特点:
- 构造器中的参数如果不被声明为 var 的话,它默认的话是 val 类型的,但一般不推荐将构造器中的参数声明为 var
- 自动创建伴生对象,同时在里面给我们实现子 apply 方法,使得我们在使用的时候可以 不直接显示地 new 对象
- 伴生对象中同样会帮我们实现 unapply 方法,从而可以将 case class 应用于模式匹配 apply 方法接受参数返回对象,unapply 方法接收对象返回参数
- 实现自己的 toString、hashCode、copy、equals 方法
- case class 主构造函数里面没有修饰符,默认的是 val
例1:
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
Notification
是一个虚基类,它有三个具体的子类Email
, SMS
和VoiceRecording
,我们可以在这些案例类(Case Class
)上像这样使用模式匹配:
def showNotification(notification: Notification): String = {
notification match {
case Email(sender, title, _) =>
s"You got an email from $sender with title: $title"
case SMS(number, message) =>
s"You got an SMS from $number! Message: $message"
case VoiceRecording(name, link) =>
s"you received a Voice Recording from $name! Click the link to hear it: $link"
}
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
println(showNotification(someSms)) // prints You got an SMS from 12345! Message: Are you there?
println(showNotification(someVoiceRecording)) // you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
showNotification
函数接受一个抽象类Notification
对象作为输入参数,然后匹配其具体类型。(也就是判断它是一个Email
,SMS
,还是VoiceRecording
)。在case Email(sender, title, _)
中,对象的sender
和title
属性在返回值中被使用,而body
属性则被忽略,故使用_
代替。
例2
package com.cw.chapter11
object Scala07_Match5 {
def main(args: Array[String]): Unit = {
// 样例类 case class
// TODO 基本介绍
// 1) 样例类仍然是类
// 2) 样例类用case关键字进行声明。
// 3) 样例类是为模式匹配(对象)而优化的类
// 4) 构造器中的每一个参数都成为val — — 除非它被显式地声明为var
// 5) 在样例类对应的伴生对象中提供apply方法让你不用new关键字就能构造出相应的对象
// 6) 提供unapply方法让模式匹配可以工作
// 7) 将自动生成toString、equals、hashCode和copy方法(有点类似模板类,直接给生成,供程序员使用)
// 8) 除上述外,样例类和其他类完全一样。你可以添加方法和字段,扩展它们
//val dollar = new Dollar(1.0)
val dollar = Dollar(1.0) // TODO 伴生对象提供apply方法,不用new
println(dollar.value)
// TODO 当我们有一个类型为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)
}
// TODO copy方法可以创建一个与现有对象值相同的新对象 ,并可以通过带名参数来修改某些属性
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(amt2)
println(amt3)
// 什么是中置表达式?1 + 2,这就是一个中置表达式。
// 如果unapply方法产出一个元组,你可以在case语句中使用中置表示法。比如可以匹配一个List序列
var list = List(1, 3, 5, 9)
list match {
case first :: second :: rest => println(first + " ** " + second + " ** " + rest)
case _ => println("匹配不到...")
}
}
}
// TODO 密封类(sealed)介绍
// 1) 如果想让case类的所有子类都必须在申明该类的相同的源文件中定义,可以将样例类的通用超类声明为sealed,这个超类称之为密封类。
// 2) 密封就是不能在其他文件中定义子类。
// 当Amount没有声明sealed时,可以在其他文件中定义样例子类,声明后就只能在本文件声明子类了
// 所有的样例类最好在同一个文件中
abstract sealed class Amount
// 说明: 这里的 Dollar,Currencry, NoAmount 是样例类。
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
case object NoAmount extends Amount
特质(trait
)和类(class
)可以用sealed标记为密封的,这意味着其所有子类都必须与之定义在相同文件中,从而保证所有子类型都是已知的。
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
def findPlaceToSit(piece: Furniture): String = piece match {
case a: Couch => "Lie on the couch"
case b: Chair => "Sit on the chair"
}
这对于模式匹配很有用,因为我们不再需要一个匹配其他任意情况的case。
例3
object Test01 {
def main(args: Array[String]): Unit = {
val arr=Array(SubmitTask("1001","zs"),
HeartBeat(10000),CheckTimeOutTask)
arr(Random.nextInt(arr.length)) match {
case SubmitTask(id,name) => println(id,name) //这里能将样例类中的参数提取出来,是是因为有unapply方法
case HeartBeat(time) => println(time)
case CheckTimeOutTask => println("CheckTimeOutTask")
}
}
}
//多例样例类
case class SubmitTask(id: String, name: String)
//多例样例类
case class HeartBeat(time: Long)
//单例样例类
case object CheckTimeOutTask
例4:
在 Scala 中 Option 类型样例类用来表示可能存在或也可能不存在的值(Option 的子类有 Some 和 None)。Some 包装了某个值,None 表示没有值。
object Test01 {
def main(args: Array[String]): Unit = {
val map=Map("name"->"zs","age"->18,"address"->"beijing")
val value=map.get("name")
val result=value match {
case Some(i) => i
case None => 0
}
println(result)
//上述方法可以用map的方法替代
map.getOrElse("name",0)
}
}
五,偏函数
偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为 List[Int],而我们需要的是第一个元素是 0 的集合,这就是通过模式匹配实现的。
偏函数定义
val second: PartialFunction[List[Int], Option[Int]] = {
case x :: y :: _ => Some(y)
}
注:该偏函数的功能是返回输入的List 集合的第二个元素
偏函数原理
上述代码会被scala
编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt
,其返回值类型为Boolean
。
val second = new PartialFunction[List[Int], Option[Int]] {
//检查输入参数是否合格
override def isDefinedAt(list: List[Int]): Boolean = list match
{
case x :: y :: _ => true
case _ => false
}
//执行函数逻辑
override def apply(list: List[Int]): Option[Int] = list match
{
case x :: y :: _ => Some(y)
}
}
偏函数使用
偏函数不能像 second(List(1,2,3))这样直接使用,因为这样会直接调用 apply 方法,而应该调用 applyOrElse
方法,如下
second.applyOrElse(List(1,2,3), (_: List[Int]) => None)
applyOrElse 方法的逻辑为if (ifDefinedAt(list)) apply(list) else default
。如果输入参数满足条件,即 isDefinedAt
返回true
,则执行apply
方法,否则执行defalut
方法,default
方法为参数不满足要求的处理逻辑。
案例实操
将该 List(1,2,3,4,5,6,“test”)中的 Int 类型的元素加一,并去掉字符串
package com.cw
/**
* @author 陈小哥cw
* @date 2021/3/31 14:28
*/
object Test {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, 5, 6, "test")
val list1 = list.map {
a =>
a match {
case i: Int => i + 1
case s: String => s + 1
}
}
println(list1.filter(a => a.isInstanceOf[Int]))
}
}
方法一:
List(1,2,3,4,5,6,"test")
.filter(_.isInstanceOf[Int])
.map(_.asInstanceOf[Int] + 1)
.foreach(println)
方法二:
List(1, 2, 3, 4, 5, 6, "test")
.collect {
case x: Int => x + 1
}
.foreach(println)
案例2
object Test01 {
def main(args: Array[String]): Unit = {
//普通方式的模式匹配
val value = "aa"
value match {
case "aa" => println("0")
case "bb" => println("1")
case "aa" => println("0")
}
/**
* 偏函数:
* 语法:func1:PartialFunction[input,output]
* input:表示输入类型
* output:输出的类型
*
*/
def func1:PartialFunction[String,Int]={
case "zs" =>18
case "ls"=>18
case "ww"=>20
case _ =>100
}
}
}