千家信息网

5、Scala模式匹配

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,一、case class用case修饰的Class 我们称之为Case Class。编译器看到这个case修饰的class,会为这个class加一些额外的特性:1、编译器会为Case Class增加一
千家信息网最后更新 2026年11月01日5、Scala模式匹配

一、case class

用case修饰的Class 我们称之为Case Class。编译器看到这个case修饰的class,会为这个class加一些额外的特性:

1、编译器会为Case Class增加一个以类名为名字的工厂方法,这个工厂方法作用是构建这个类的对象

val v = Var("x") //构建对象的时候不需要用new关键词

2、编译器默认的为case class的值参数加上了val来进行修饰,所以这些值参数和一个类里的域一样

v.name

3、编译器自动为case class添加了toString、hashCode以及equals方法。可以用 == 来比较case class,比较case class的类型以及case class中的值参数

op.right == Var("x")

4、编译器为case class增加了一个copy方法,使得case class的值参数的值可以修改。如果一个case class中只要几个特定的值参数需要改变的话,用copy比较方便。

val opNew = op.copy(operator = "-")

case 除了可以修饰class,还可以修饰object,就是表示一个单例对象

case class最大的优点就是配合模式匹配

二、Scala的match表达式 和java switch区别

1、Scala的match表达式可以计算出一个值,而Java的switch却不能

2、模式匹配的表达式永远不会穿透到下一个case表达式中, java的switch中没有break的话,则会穿透到下一个分支

3、模式匹配中如果没有任何的模式被匹配到,则抛出MatchError异常

三、SealedClass

当你在用模式匹配的时候,你肯定需要考虑所有场景的case,有的时候我们可以用default来代替所有没有考虑到的情况,但是有的时候这个默认值没有意义,这个时候怎么来保证你能考虑到所有的情况呢?我们让编译器来帮我们考虑,我们可以在case class的父类上加一个sealed的关键字,这个sealed会帮我们做两件事情:

1:在我们定义模式匹配的时候,如果没有考虑全场景,编译器会报警告

2:被sealed修饰的类,不能被在其他文件中的case class继承

四、模式的种类

1、通配符模式 case _ 可以用于匹配默认的场景,可以用于可以忽略的对象的域的情况

2、常量模式

def describe(x: Any) = x match {

case 5 => "five"

case true => "truth"

case "hello" => "hi!"

case Nil => "the empty list"

case _ => "something else"

}

describe(5) //res6: String = five

describe(true) //res7: String = truth

describe("hello") //res8: String = hi!

describe(Nil) //res9: String = the empty list

describe(List(1, 2, 3)) //res10: String = something else

3、变量模式

可以将被匹配的表达式的值绑定到模式中的变量中,这样可以在expressions中使用这个变量

val i = 1 + 1

var result = i match {

case 0 => "zero"

case somethingElse => "not zero: " + somethingElse

}

println(result) // not zero: 2

编译器怎么判断是常量模式还是变量模式?

val pi = math.Pi

result = E match {

case pi => "strange math? Pi = " + pi //以小写字母开头的单词被编译器认为是变量模式

}

result = E match {

case `pi` => "strange math? Pi = " + pi //以反引号扩起来的为常量模式

case _ => "OK"

}

4、构造器模式。支持深度匹配

5、序列模式。支持固定长度的序列或者数组,也支持非固定长度。

v match {

case List(0, _*) => println("list it")//匹配含有任意个元素的List,并且第一个元素等于0

case Array(0, _*) => println("array it")//匹配含有任意个元素的Array,并且第一个元素等于0

case _ =>

}

6、元组模式

def tupleDemo(expr: Any) = expr match {

case (a, b, c) => println("matched " + a + b + c)

case _ =>

}

7、类型模式

def generalSizeWithPattern(x: Any) = x match {

case s: String => s.length

case m: Map[Int, Int] => m.size

case _ => -1

}

关于类型擦除,数组是个例外,因为数组在java中是特殊处理了,在scala中也是特殊处理了,在jvm中对应着不同类型的数组,比如int[], float[]等

isIntIntMap(Map(1 -> 1)) //true

isIntIntMap(Map("abc" -> "abc")) //true


isStringArray(Array("abc")) //yes

isStringArray(Array(1, 2, 3)) //no

8、变量绑定

val expr = UnOp("abs", UnOp("abs", Var("x")))

expr match {

case UnOp("abs", e@UnOp("abs", i@Var(_))) => println(e + " " + i)

case _ =>

}

五、模式守卫

在模式中可以定义条件。

def simplifyAdd(e: Expr) = e match {

case BinOp("+", a, b) if a == b => BinOp("*", b, Number(2))

case _ => e

}

六、模式重叠

尽量避免模式重叠

def simplifyBad(expr: Expr): Expr = expr match {

case UnOp("-", UnOp("-", e)) => e //第一个case

case UnOp(op, e) => UnOp(op, simplifyBad(e)) //第二个case

}

当case1属于case2的子集,那么case1可以放在case2之前,若放在case2之后,则永远无法执行,编译器会报警告unreachable code.

七、Option

Option视作一个容器,可以有东西,也可以没有东西。Some 表示有且仅有一个东西 None表示没有东西

val opt = Some("aaa")

opt.getOrElse("default")


在模式匹配中使用:

val capitals =

Map("France" -> "Paris", "Japan" -> "Tokyo")

def show(x: Option[String]) = x match {

case Some(s) => s

case None => "?"

}

show(capitals get "Japan") //res25: String = Tokyo

show(capitals get "France") //res26: String = Paris

show(capitals get "North Pole") //res27: String = ?


八、模式在变量定义中的使用

val myTuple = (123, "abc")

val (number, string) = myTuple


val exp = new BinOp("*", Number(5), Number(1))

val BinOp(op, left, right) = exp

九、模式在偏函数中使用

1、一个case序列作为全函数(complete function)

val withDefault: Option[Int] => Int = {

case Some(x) => x

case None => 0

}

2、如果缺少了一个case会出现什么情况呢?编译会出现警告

val second: Option[Int] => Int = {

case Some(x) => x

}

3、如果我们的case列表是部分的场景,我们需要告诉编译器这是一个偏函数(partial function)

val partial : PartialFunction[Option[Int], Int] = {

case Some(x) => x

}

4、我们尽可能的用全函数,因为偏函数如果没有考虑清楚需要处理的case的话,可能会抛异常。

上面的partial就是和下面的p是一个意思

val p = new PartialFunction[Option[Int], Int] {

override def isDefinedAt(x: Option[Int]) = x match {

case Some(_) => true

case None => false

}


override def apply(v1: Option[Int]) = v1 match {

case Some(x) => x

}


5、如果要使用偏函数,推荐用下面模式

if (partial.isDefinedAt(None)) {

partial(None) //如果单独运行的话,还是会抛异常

}

十、模式在for中使用

val results = List(Some("apple"), None, Some("orange"))

for (Some(fruit) <- results) println(fruit)


val capitals =

Map("France" -> "Paris", "Japan" -> "Tokyo")

for ((country, city) <- capitals)

println("The capital of " + country + " is " + city)

十一、萃取器unapply

含有成员方法unapply的object,我们称之为extractors(萃取器)。extractors可以同时定义apply(可选的)和unapply方法。


模式 编译 编译器 变量 函数 方法 时候 参数 表达式 东西 元素 场景 对象 情况 数组 类型 就是 常量 序列 处理 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司 华服互联网科技靠谱吗 互联网科技工作委员会主任 工业互联网科技新基建 互联网下的科技发展 亿策互联网科技 华中科技大学互联网 中国最先进互联网科技公司 青岛中康互联网医疗科技有限公司 米聚互联网科技南京有限公司排面 浙南科技城互联网大厦建设工程 内蒙古九一互联网科技 恒生互联网科技业指数调整周期 江苏苏星互联网科技有限公司 广州百诚互联网科技有限公司官网 科技信息时代互联网发展 米泉互联网科技专业怎么样 互联网科技和医药行业 广西泛欧互联网科技有限公司 前海云享互联网科技 互联网最新的科技 与互联网科技公司 西安互联网科技公司 居家互联网科技有限公司 互联网科技公司招聘 北京三清互联网科技 崇明区互联网教育科技售后服务 35岁以上互联网科技行业 恒生科技互联网指数十大成分股 前海云享互联网科技
0