在前面的章节已经讲了Scala中的简单模式匹配。模式匹配是一个表达式,因此它会导致一个值,该值可能被分配或返回。例如:
44 match {
case 44 => true // 如果匹配了44,则结果为true
case _ => false // 否则,结果是false
}
也可以匹配字符串,例如:
"过期商品" match {
case "过期商品" => .45
case "未过期商品" => .77
case _ => 1.0
}
可用模式匹配实现java中switch语句功能:
val status = 500
val message = status match {
case 200 => "ok"
case 400 => {
println("ERROR - 调用的服务不正确")
"error"
}
case 500 => {
println("ERROR - 服务器遇到了问题")
"error"
}
}
val day = "MON"
val kind = day match {
case "MON" | "TUE" | "WED" | "THU" | "FRI" => "工作日"
case "SAT" | "SUN" => "周末"
}
Scala强大的模式匹配机制,可以应用在switch语句、类型检查以及“析构”等场合。
def swithOps: Unit ={
var sign = 0
val ch: Char = '+'
ch match {
case '+' => sign = 1
case '-' => sign = -1
case _ => sign = 0
}
println("sign===> " + sign)
}
swithOps
上面代码中,case _模式对应于switch语句中的default,能够捕获剩余的情况。如果没有模式能匹配,会抛出MatchError。而且不像常见的switch语句,在一种模式匹配之后,需要使用break来声明分支不会进入下一个分支,在scala中并不需要这种break语句。
另外,match是表达式,不是语句,所以是有返回值的,故可将代码简化:
sign = ch match {
case '+' => 1
case '-' => -1
case _ => 0
}
println("sign=====> "+ sign)
Scala中的任何表达式都是有返回值的,模式匹配也不例外,我们可以直接获取对应的返回值进行操作。如果不写case _的操作,匹配不上的话,会抛出相关异常:scala.MatchError。
def caseOps2: Unit = {
val ch = '1'
val sign = ch match {
case '+' => 1
case '-' => 0
// case _ => 2
}
println(sign)
}
一般情况下也就是将模式匹配当做java中的switch case来进行使用的。
如果在case关键字后跟着一个变量名,那么匹配的表达式会被赋值给那个变量。case _ 是这个特性的一个特殊情况,变量名是_。
// 将要进行匹配的值,赋值给case后面的变量,我们可以对变量进行各种操作
def caseOps4: Unit = {
"Hello, wordl" foreach(c => println(
c match {
case ' ' => "space"
case ch => "Char: " + ch
}
))
}
caseOps4
基本模式匹配
下面的代码演示了基本模式匹配的使用:
def printNum(int: Int) {
int match {
case 0 => println("Zero")
case 1 => println("One")
case _ => println("more than one")
}
}
printNum(0)
printNum(1)
printNum(2)
def fibonacci(in: Int): Int = in match {
case 0 => 0
case 1 => 1
case n => fibonacci(n - 1) + fibonacci(n - 2)
}
fibonacci(10)
def fib1(in: Int): Int = in match {
case 0 | -1 | -2 => 0
case 1 => 1
case n => fibonacci(n - 1) + fibonacci(n - 2)
}
// 条件守护
def fib2(in: Int): Int = in match {
case n if n <= 0 => 0
case 1 => 1
case n => fib2(n - 1) + fib2(n - 2)
}
模式匹配和在case子句中使用if表达式
可以通过在case语句中添加if表达式来模拟OR子句。
object demo {
def main(args: Array[String]): Unit = {
println("\n模式匹配和在case子句中使用if表达式")
// val fruitType = "水果布丁"
// val fruitType = "杨桃"
val fruitType = "随便"
val tasteLevel = fruitType match {
case fruit if fruit.contains("水果") || fruit.contains("布丁") => "肯定很美味"
case "杨桃" => "尝一尝"
case _ => "可以尝一尝"
}
println(s"${fruitType}的味道 = $tasteLevel")
}
}
匹配元组
object demo {
def main(args: Array[String]): Unit = {
val one = ("张三", "男", 25000.00)
val two = ("李四", "男", 30000.00)
val three = ("小美", "女", 18000.00)
val allList = List(one, two, three)
// 元组匹配
val priceOfPlainDonut = allList.foreach { tuple => {
tuple match {
case ("张三", gender, salary) => println(s"张三, 性别=$gender, 薪资=$salary")
case d if d._1 == "张三" => println(s"${d._1}, 性别=${d._2}, 薪资=${d._3}")
case _ => None
}
}
}
}
}
执行以上代码,输出结果如下:
张三, 性别=男, 薪资=25000.0
以上模式匹配更优雅的写法:
object demo {
def main(args: Array[String]): Unit = {
val one = ("张三", "男", 25000.00)
val two = ("李四", "男", 30000.00)
val three = ("小美", "女", 18000.00)
val allList = List(one, two, three)
// 更优雅的写法
allList.foreach {
case ("张三", gender, salary) => println(s"张三, 性别=$gender, 薪资=$salary")
case d if d._1 == "张三" => println(s"${d._1}, 性别=${d._2}, 薪资=${d._3}")
case _ => None
}
}
}
匹配Option类型
object demo {
def main(args: Array[String]): Unit = {
val title:Option[String] = Some("老板")
// val title:Option[String] = None
title match{
case Some(a) => println(s"title是$a。")
case None => println(s"没有title,屌丝一个。")
}
}
}
匹配Any类型
下面的代码演示了如何将模式匹配应用于Any类型的数据:
val anyList= List(1, "A", 2, 2.5, 'a')
for (m <- anyList) {
m match {
case i: Int => println("Integer: " + i)
case s: String => println("String: " + s)
case f: Double => println("Double: " + f)
case other => println("other: " + other)
}
}
使用模式匹配可以代替isInstanceOf和asInstanceOf来进行使用。相比使用isInstanceOf来判断类型,使用模式匹配更好。
def caseOps5: Unit = {
def typeOps(x: Any): Int = {
val result = x match {
case i: Int => i
case s: String => Integer.parseInt(s)
case z: scala.math.BigInt => Int.MaxValue
case c: Char => c.toInt
case _ => 0
}
result
}
println(typeOps("12345") == 12345)
}
caseOps5
可以通过模式匹配进行类型匹配。例如:
object demo06 {
def main(args: Array[String]): Unit = {
println("\n按类型匹配模式")
val priceOfFruit: Any = 2.50
val priceType = priceOfFruit match {
case price: Int => "Int"
case price: Float => "Float"
case price: Double => "Double"
case price: String => "String"
case price: Boolean => "Boolean"
case price: Char => "Char"
case price: Long => "Long"
}
println(s"水果价格类型 = $priceType")
}
}
执行以上代码,输出结果如下:
按类型匹配模式
水果价格类型 = Double
下面的代码同样演示了怎样通过模式匹配判断变量的数据类型:
def test2(in: Any) = in match {
case s: String => "字符串,长度是" + s.length
case i: Int if i > 0 => "自然整数"
case i: Int => "整数"
case a: AnyRef => a.getClass.getName
case _ => "null"
}
匹配List类型
也可以使用模式匹配来匹配数组、列表和元组:
def caseOps6: Unit = {
val arr = Array(0, 1)
arr match {
// 匹配只有一个元素的数组,且元素就是0
case Array(0) => println("0")
// 匹配任何带有两个元素的数组,并将元素绑定到x和y
case Array(x, y) => println(x + " " + y)
// 匹配任何以0开始的数组
case Array(0, _*) => println("0 ...")
case _ => println("something else")
}
}
caseOps6
下面的代码演示了如何将模式匹配应用于List类型的数据:
val x = 1
val rest = List(2,3,4)
x :: rest
// 模式匹配:即可以比较,也可以提取值
(x :: rest) match { // 注意创造和匹配之间的对称性
case Nil => 0
case x :: rest => println(x); println(rest)
}
下面的代码使用模式匹配对所有奇数求和:
def sumOdd(in: List[Int]): Int = in match {
case Nil => 0
case x :: rest if x % 2 == 1 => x + sumOdd(rest)
case _ :: rest => sumOdd(rest) // 忽略第1个元素
}
val list1 = List(2,3,4)
sumOdd(list1)
下面的代码匹配List中任意数量的元素:
def noPairs[T](in: List[T]): List[T] = in match {
case Nil => Nil
case a :: b :: rest if a == b => noPairs(a :: rest) // 如果前两个元素相同,排除连续重复的元素
case a :: rest => a :: noPairs(rest)
}
noPairs(List(1,2,3,3,3,4,1,1))
模式匹配既可以匹配常量,也可以提取信息:
def ignore(in: List[String]): List[String] = in match {
case Nil => Nil
case _ :: "ignore" :: rest => ignore(rest)
case x :: rest => x :: ignore(rest)
}
使用类测试/强制转换机制查找List[Any]中的所有字符串:
def getStrings(in: List[Any]): List[String] = in match {
case Nil => Nil
case (s: String) :: rest => s :: getStrings(rest)
case _ :: rest => getStrings(rest)
}
模式匹配与case class
模式匹配也可以对两个case class进行匹配:
case class Person(name: String, age: Int, valid: Boolean)
val p = Person("张三", 45, true)
// 也可以
val m = new Person("李四", 24, true)
def older(p: Person): Option[String] = p match {
case Person(name, age, true) if age > 35 => Some(name)
case _ => None
}
older(p).get
older(p).getOrElse("匿名")
// older(m).get // 会出现异常
older(m).getOrElse("匿名")
样例类(case class)的模式匹配
下面这个示例代码,演示了如何匹配多个case object:
trait Command
case object Start extends Command
case object Go extends Command
case object Stop extends Command
case object Whoa extends Command
def executeCommand(cmd: Command) = cmd match {
case Start | Go => println("starting")
case Stop | Whoa => println("stopping")
case default => println("You gave me: " + default) // 可访问default值
}
executeCommand(Start)
executeCommand(Whoa)
模式匹配作为参数
模式匹配可作为参数传递给其他函数或方法,编译器会将模式匹配编译为函数:
val list = List("aa",123,"ss",456,"dd")
list.filter(a => a match {
case s: String => true
case _ => false
})
// 上面的代码可简化为
list.filter {
case s: String => true
case _ => false
}
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
暂无评论内容