首页 > 其他分享 >Scala模式匹配

Scala模式匹配

时间:2022-11-11 16:33:44浏览次数:54  
标签:case 匹配 val Scala 模式匹配 println Array match


1  switch

与default等效的是捕获所有的case_ 模式。如果没有模式匹配,抛出MatchError,每个case中,不用break语句。可以在match中使用任何类型,而不仅仅是数字。

var result = 0;
val op : Char = '-'

op match {
case '+' => result = 1
case '-' => result = -1
case _ => result = 0
}
println(result)

2  守卫

像if表达式一样,match也提供守卫功能,守卫可以是任何Boolean条件

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 = 0
}
println(ch + " " + sign + " " + digit)
}

3  模式中的变量

如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量。

val str = "+-3!"
for (i <- str.indices) {
var sign = 0
var digit = 0

str(i) match {
case '+' => sign = 1
case '-' => sign = -1
case ch if Character.isDigit(ch) => digit = Character.digit(ch, 10)
case _ =>
}
println(str(i) + " " + sign + " " + digit)
}

4  类型模式

可以匹配对象的任意类型,但是不能直接匹配泛型类型,这样描述比较抽象,看下面的例子:这样做的意义在于,避免了使用isInstanceOf和asInstanceOf方法。

val a = 8
val obj = if(a == 1) 1
else if(a == 2) "2"
else if(a == 3) BigInt(3)
else if(a == 4) Map("aa" -> 1)
else if(a == 5) Map(1 -> "aa")
else if(a == 6) Array(1, 2, 3)
else if(a == 7) Array("aa", 1)
else if(a == 8) Array("aa")
val r1 = obj match {
case x: Int => x
case s: String => s.toInt
case BigInt => -1 //不能这么匹配
case _: BigInt => Int.MaxValue
case m: Map[String, Int] => "Map[String, Int]类型的Map集合"
case m: Map[_, _] => "Map集合"
case a: Array[Int] => "It's an Array[Int]"
case a: Array[String] => "It's an Array[String]"
case a: Array[_] => "It's an array of something other than Int"
case _ => 0
}
println(r1 + ", " + r1.getClass.getName)

尖叫提示:Map类型的泛型在匹配的时候,会自动删除泛型类型,只会匹配到Map类型,而不会精确到Map里面的泛型类型。

5  匹配数组、列表、元组

Array(0) 匹配只有一个元素且为0的数组。

Array(x,y) 匹配数组有两个元素,并将两个元素赋值为x和y。

Array(0,_*) 匹配数组以0开始。

1)  匹配数组

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(x, y, z) => x + " " + y + " " + z
case Array(0, _*) => "0..."
case _ => "something else"
}
println(result)
}

2)  匹配列表

与匹配数组相似,同样可以应用于列表

for (lst <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
val result = lst match {
case 0 :: Nil => "0"
case x :: y :: Nil => x + " " + y
case 0 :: tail => "0 ..."
case _ => "something else"
}
println(result)
}

3)  匹配元组

同样可以应用于元组

for (pair <- Array((0, 1), (1, 0), (1, 1))) {
val result = pair match {
case (0, _) => "0 ..."
case (y, 0) => y + " 0"
case _ => "neither is 0"
}
println(result)
}

6  提取器

模式匹配,什么才算是匹配呢?即,case中unapply方法返回some集合则为匹配成功,返回none集合则为匹配失败。下面我们来看几个例子做详细探讨。

1) unapply

--调用unapply,传入number

--接收返回值并判断返回值是None,还是Some

--如果是Some,则将其解开,并将其中的值赋值给n(就是case Square(n)中的n

创建object Square:
object Square {
def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
}
模式匹配使用:
val number: Double = 36.0
number match {
case Square(n) => println(s"square root of $number is $n")
case _ => println("nothing matched")
}

2) unapplySeq

--调用unapplySeq,传入namesString

--接收返回值并判断返回值是None,还是Some

--如果是Some,则将其解开

--判断解开之后得到的sequence中的元素的个数是否是三个

--如果是三个,则把三个元素分别取出,赋值给first,second和third

创建object Names:
object Names {
def unapplySeq(str: String): Option[Seq[String]] = {
if (str.contains(",")) Some(str.split(","))
else None
}
}
模式匹配使用:
val namesString = "Alice,Bob,Thomas"
namesString match {
case Names(first, second, third) => {
println("the string contains three people's names")
println(s"$first $second $third")
}
case _ => println("nothing matched")
}

7  变量声明中的模式

match中每一个case都可以单独提取出来,意思是一样的,如下:

val (x, y) = (1, 2)
val (q, r) = BigInt(10) /% 3
val arr = Array(1, 7, 2, 9)
val Array(first, second, _*) = arr
println(first, second)

8  for表达式中的模式

import scala.collection.JavaConverters._
for ((k, v) <- System.getProperties.asScala)
println(k + " -> " + v)

for ((k, "") <- System.getProperties.asScala)
println(k)

for ((k, v) <- System.getProperties.asScala if v == "")
println(k)

尖叫提示:for中匹配会自动忽略失败的匹配

9  样例类

样例类首先是类,除此之外它是为模式匹配而优化的类,样例类用case关键字进行声明:

1)  样例类的创建

package unit6

abstract class Amount
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
case object Nothing extends Amount

2)  当我们有一个类型为Amount的对象时,我们可以用模式匹配来匹配他的类型,并将属性值绑定到变量:

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

当你声明样例类时,如下几件事情会自动发生:

--构造其中的每一个参数都成为val——除非它被显式地声明为var(不建议这样做)

--在半生对象中提供apply方法让你不用new关键字就能构造出相应的对象,比如Dollar(29.95)或Currency(29.95, "EUR")

--提供unapply方法让模式匹配可以工作

--将生成toString、equals、hashCode和copy方法——除非显式地给出这些方法的定义。

除上述外,样例类和其他类型完全一样。你可以添加方法和字段,扩展它们。

10  Copy方法和带名参数

copy创建一个与现有对象值相同的新对象,并可以通过带名参数来修改某些属性。

val amt = Currency(29.95, "EUR")
val price = amt.copy(value = 19.95)
println(amt)
println(price)
println(amt.copy(unit = "CHF"))

11  Case语句的中置(缀)表达式

什么是中置表达式?1 + 2,这就是一个中置表达式。如果unapply方法产出一个元组,你可以在case语句中使用中置表示法。比如可以匹配一个List序列。

List(1, 7, 2, 9) match {
case first :: second :: rest => println(first + second + rest.length)
case _ => 0
}

12  匹配嵌套结构

比如某一系列商品想捆绑打折出售

1)  创建样例类

abstract class Item
case class Article(description: String, price: Double) extends Item
case class Bundle(description: String, discount: Double, item: Item*) extends Item

2)  匹配嵌套结构

val sale = Bundle("愚人节大甩卖系列", 10,
Article("《九阴真经》", 40),
Bundle("从出门一条狗到装备全发光的修炼之路系列", 20,
Article("《如何快速捡起地上的装备》", 80),
Article("《名字起得太长躲在树后容易被地方发现》",30)))

3)  将descr绑定到第一个Article的描述

val result1 = sale match {
case Bundle(_, _, Article(descr, _), _*) => descr
}
println(result1)

4)  通过@表示法将嵌套的值绑定到变量。_*绑定剩余Item到rest

val result2 = sale match {
case Bundle(_, _, art @ Article(_, _), rest @ _*) => (art, rest)
}
println(result2)

5)  不使用_*绑定剩余Item到rest

val result3 = sale match {
case Bundle(_, _, art @ Article(_, _), rest) => (art, rest)
}
println(result3)

6)  计算某个Item价格的函数,并调用

def price(it: Item): Double = {
it match {
case Article(_, p) => p
case Bundle(_, disc, its@_*) => its.map(price _).sum - disc
}
}

println(SwitchBaseSyllabus.price(sale))

13  密封类

如果想让case类的所有子类都必须在申明该类的相同的文件中定义,可以将样例类的通用超类声明为sealed,叫做密封类,密封就是外部用户不能在其他文件中定义子类。

14  模拟枚举

样例类可以模拟出枚举类型

1)  创建密封样例类(不密封也可以,在这里只是为了用一下sealed关键字)

package unit6
sealed abstract class TrafficLightColor
case object Red extends TrafficLightColor
case object Yellow extends TrafficLightColor
case object Green extends TrafficLightColor

2)  模拟枚举

for (color <- Array(Red, Yellow, Green))
println(
color match {
case Red => "stop"
case Yellow => "slowly"
case Green => "go"
})

15  偏函数

偏函数,它只对会作用于指定类型的参数或指定范围值的参数实施计算

val f: PartialFunction[Char, Int] = {
case '+' => 1
case '-' => -1
}
println(f('-'))
println(f.isDefinedAt('0'))
println(f('+'))
// println(f('0'))

再深入探讨一点点:

我们定义一个将List集合里面数据+1的偏函数:

val f1 = new PartialFunction[Any, Int] {
def apply(any: Any) = any.asInstanceOf[Int] + 1

def isDefinedAt(any: Any) = if (any.isInstanceOf[Int]) true else false
}
val rf1 = List(1, 3, 5, "seven") collect f1
println(rf1)

如上的功能,等同于:

def f2: PartialFunction[Any, Int] = {
case i: Int => i + 1
}
val rf2 = List(1, 3, 5, "seven") collect f2
println(rf2)

标签:case,匹配,val,Scala,模式匹配,println,Array,match
From: https://blog.51cto.com/u_12654321/5845145

相关文章

  • Scala数据结构
    1 数据结构特点Scala同时支持可变集合和不可变集合,不可变集合从不可变,可以安全的并发访问。两个主要的包:不可变集合:scala.collection.immutable可变集合: scala.collecti......
  • Scala 类
    1 简单类和无参方法类的定义可以通过class关键字实现,如下:packageunit7classDog{privatevarleg=4defshout(content:String){println(content)}def......
  • Scala高阶函数
    1 作为参数的函数函数作为一个变量传入到了另一个函数中,那么该作为参数的函数的类型是:function1,即:(参数类型)=>返回类型defplus(x:Int)=3+xvalresult1=Array(1,......
  • Scala注解
    注解就是标签。标签是用来标记某些代码需要特殊处理的。处理的手段可以在代码运行时操作,也可以在编译期操作。1 什么可以被注解1) 可以为类,方法,字段局部变量,参数,表达式,......
  • 【THM】Linux Privilege Escalation(Linux权限提升基础)-学习
    本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/linprivesc通过学习相关知识点:了解Linux权限提升的基础知识,从枚举到利用,了解多种不同的权限提升技术。介......
  • Scalable Evaluation of Multi-Agent Reinforcement Learning with Melting Pot
    提出的问题:现有的对多智能体强化学习的评估工具没有将多智能体强化学习泛化的新情况评估作为主要目标。传统的监督学习和受益于明确的实验环境和存在的评价基准,能够较为......
  • [scala基础]--拆分List操作
    运行环境:Jdk1.7、scala-2.10.4packagestudy/***Document:本类作用---->拆分List*User:yangjf*Date:2016/8/148:57*/objectTestArrays{defmain(args:A......
  • Spark简单介绍,Windows下安装Scala+Hadoop+Spark运行环境,集成到IDEA中
    一、前言近几年大数据是异常的火爆,今天小编以java开发的身份来会会大数据,提高一下自己的层面!大数据技术也是有很多:HadoopSparkFlink小编也只知道这些了,由于Hadoop,......
  • C#中的模式匹配
    C#从7.0开始,陆陆续续推出了各种模式匹配,模式是一种特殊的表达式,通过判断给定的值是否满足此表达式而返回true或者false,它就类似于正则表达式的作用。目前(C#9.0),可......
  • 【scala】getclass的使用
    打印属性名判断是否有该属性......