强大的Scala模式匹配
用过Scala的模式匹配,感觉Java的弱爆了。Scala几乎可以匹配任何数据类型,如果默认的不能满足你的要求,你可以自定义模式匹配。
介绍Scala的模式匹配前,我们先了解清楚unapply()与unapplySeq()两个方法:
名字叫做unapply和unapplySeq的方法在Scala里也是有特殊含义的。
我们前面说过case class在做pattern match时非常好用,而除case class之外,有unapply或unapplySeq方法的对象在pattern match时也有非常好的应用场景。
比方这段代码:
1 |
|
我们定义了一个unapply方法,用来计算平方根。
我们能够像调用普通方法一样的调用它:
1 |
|
这样会得到36的平方根:6。实际上返回值是Some(6)。
上面的方式是对unapply的浪费。unapply真正的优点是这种:
1 |
|
这样我们无需显式调用unapply方法,而把是它用在pattern match中。让编译器替我们调用它。
当我们写下这段pattern match的代码时,编译器事实上替我们做了好几件事:
- 调用unapply,传入number
- 接收返回值并推断返回值是None,还是Some
- 假设是Some,则将其解开,并将当中的值赋值给n(就是case Square(n)中的n)
这段代码反编译出来是这个样子的:
1 |
|
假设没有unapply方法和pattern match语法之间的这样的结合,我们自己写代码要写成什么样子呢?
也许会比上面反编译的代码简单一些,可是显式地调用开平方的方法。用if else来推断Option,以及将真正的返回值从Option里面解出来这三件事是免不掉的。
unapplySeq和unapply的作用非常是类似,比如这样:
1 |
|
我们定义一个unapplySeq方法,用逗号作为分隔符来把字符串拆开。
然后我们能够这样应用它:
1 |
|
与上面的样例非常是类似,只是编译器在这里替我们做的事情很多其它了:
- 调用unapplySeq,传入namesString
- 接收返回值并推断返回值是None,还是Some
- 假设是Some,则将其解开
- 推断解开之后得到的sequence中的元素的个数是否是三个
- 假设是三个,则把三个元素分别取出,赋值给first,second和third
假设没有unapplySeq方法和pattern match语法之间的这样的结合,我们自己写代码来做这五件事会显得非常是繁琐。
大家了解清楚unapply()与unapplySeq()两个方法,我就举个很实用的例子。
现实中往往我们有这样的一个需求:比如http请求返回体为json字符串,我们往往只需要获取json中的部分字段值。
这个需求,Java的做法是,必须知道所有json中所有字段及类型,并定义对应的JavaBean,将返回的json字符串先转换为对应的JavaBean,再通过javaBean获取想要的字段信息。
那么Scala使用模式匹配就很轻松搞定直接获取想要的字段值。如下:
先定义一个unapplySeq()实现json的模式匹配(另json字符串插值写法可参考我以前文章:Scala字符串插值 - StringContext):
package spray.json
import scala.collection.SortedMap
class JsonInterpolation(sc: StringContext) {
object json {
def apply(args: JsValue*): JsValue =
new JsonParser(ParserInput(sc, args), true).parseJsValue()
def unapplySeq(input: JsValue): Option[Seq[JsValue]] = {
val placeHolders = Seq.range(0, sc.parts.length-1).map(x => JsNumber(Integer.MAX_VALUE - x) )
val pi = ParserInput(sc, placeHolders)
val pattern = new JsonParser(pi, true).parseJsValue()
val results = collection.mutable.ArrayBuffer[JsValue]()
Seq.range(0, sc.parts.length-1).foreach { x => results += null }
try {
patternMatch(pattern, input, placeHolders, results)
Some(results.toSeq)
}
catch {
case ex: Throwable => None
}
}
// TODO report friendly
private def patternMatch(pattern: JsValue, input: JsValue, placeHolders: Seq[JsValue], results: collection.mutable.ArrayBuffer[JsValue]): Unit = {
def isPlaceHolder(value: JsNumber) = {
val num = value.value.toInt
val index = Integer.MAX_VALUE - num.toInt
num > 0 && index < placeHolders.size && placeHolders(index).eq(value)
}
pattern match {
case x: JsObject =>
x.fields.foreach {
case (key, n @ JsNumber(num)) if isPlaceHolder(n) =>
val index = Integer.MAX_VALUE - num.toInt
assert(input.asJsObject.fields contains key)
results(index) = input.asJsObject.fields(key)
case (key, value) =>
assert(input.asJsObject.fields contains key)
patternMatch(value, input.asJsObject.fields(key), placeHolders, results)
}
case x: JsArray =>
assert(input.isInstanceOf[JsArray])
assert(input.asInstanceOf[JsArray].elements.size >= x.elements.size)
x.elements.zipWithIndex.foreach {
case (x: JsNumber, y: Int) if isPlaceHolder(x) =>
val index = Integer.MAX_VALUE - x.value.toInt
results(index) = input.asInstanceOf[JsArray].elements(y)
case (x: JsValue,y: Int)=>
patternMatch(x, input.asInstanceOf[JsArray].elements.apply(y), placeHolders, results)
}
case x: JsString =>
assert(x == input)
case x: JsBoolean =>
assert(x == input)
case x: JsNumber =>
assert(x == input)
case x@ JsNull =>
assert(x == input)
}
}
}
}
定义好unpplySeq(),那么下面就看下如何通过模式匹配获取json字符传中我们关系的字段值:
import spray.json._ /**
* 类功能描述:
*
* @author WangXueXing create at 19-5-11 下午10:37
* @version 1.0.0
*/
object ObjectMatch {
def main(args: Array[String]): Unit = {
val json = json"""{"id": 12333,"sku_no":"sku35352523"}"""
json match {
case json"""{"sku_no": $skuNo}""" => println(skuNo)
case _ => println(json)
} }
}
输出:
"sku35352523"
如上,我们就可以选择性的拿到sku_no字段的值,是不是轻松搞定!
强大的Scala模式匹配的更多相关文章
- scala模式匹配详细解析
一.scala模式匹配(pattern matching) pattern matching可以说是scala中十分强大的一个语言特性,当然这不是scala独有的,但这不妨碍它成为scala的语言的一 ...
- scala模式匹配的使用
Scala模式匹配 Tip1:模式总是从上往下匹配,如果匹配不到则匹配case_项(类似Java中的default) Tip2:与Java和C语言不同,不需要在每个分支末尾使用break语句退出(不会 ...
- Spark记录-Scala模式匹配
Scala模式匹配 模式匹配是Scala函数值和闭包后第二大应用功能.Scala为模式匹配提供了极大的支持,处理消息. 模式匹配包括一系列备选项,每个替代项以关键字大小写为单位.每个替代方案包括一个模 ...
- Scala模式匹配和类型系统
1.模式匹配比java中的switch case强大很多,除了值,类型,集合等进行匹配,最常见的Case class进行匹配,Master.scala有大量的模式匹配. Case "_&qu ...
- scala模式匹配与样例类
样本类:添加了case的类便是样本类.这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定.如下: 1.添加与类名一致的工厂方法.也就是说,可以写成Var("x") ...
- Scala模式匹配| 隐式转换
1. 模式匹配 Scala中的模式匹配类似于Java中的switch语法,但是更加强大.模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分 ...
- Scala模式匹配和样例类
Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句.类型检查等.并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配. 1.字符匹配 def mai ...
- 10、scala模式匹配
一.模式匹配1 1.介绍 模式匹配是Scala中非常有特色,非常强大的一种功能.模式匹配,其实类似于Java中的swich case语法,即对一个值进行条件判断,然后针对不同的条件, 进行不同的处理. ...
- 12. Scala模式匹配
12.1 match 12.1.1 基本介绍 Scala中的模式匹配类似于Java中的switch语法,但是更加强大 模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需 ...
随机推荐
- Java JDK和IntelliJ IDEA 配置及安装
序言 初学java,idea走一波先.安装完成,配置配置项. idea 软件 官方下载地址:https://www.jetbrains.com/idea/download/#section=windo ...
- CentOS7系统yum方式安装MySQL5.7
参考:https://www.cnblogs.com/bigbrotherer/p/7241845.html#top 1.在CentOS中默认安装有MariaDB,这个是MySQL的分支,但为了需要, ...
- Winform中设置ZedGraph的曲线符号Symbol以及对应关系
场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...
- python numba讲解
目录 一:什么是numba 二:如何使用numba 由于python有动态解释性语言的特性,跑起代码来相比java.c++要慢很多,尤其在做科学计算的时候,十亿百亿级别的运算,让python的这种 ...
- php 使用fsockopen 发送http请求
需求背景 在公司开发这么一个需求,每天三次定时催付待客服催付状态的订单,设定每天15.16.17点三次执行job任务来给一批订单打电话催付,需要三个时间点都把待客服催付的订单拨打一遍电话,根据数据组统 ...
- CSS函数大全
CSS函数(方法)参考 CSS函数用作各种CSS属性的值. 函数 描述 attr() 返回所选元素的属性值 calc() 允许您执行计算以确定CSS属性值 cubic-bezier() 定义Cubic ...
- Mobx总结以及mobx和redux区别
Mobx解决的问题 传统react使用的数据管理库为Redux.Redux要解决的问题是统一数据流,数据流完全可控并可追踪.要实现该目标,便需要进行相关的约束 Redux由此引出dispatch ac ...
- SVG撑满页面
当viewBox属性固定,默认修改svg标签的宽高,svg都会按比例缩放 我们现在不想按比例缩放,需要svg撑满整个画面 这里只需为svg标签添加一个关键属性:preserveAspectRatio ...
- ssh关闭服务关闭 nohup
默认输出 # nohup cmd & 指定输出路径 # nohup cmd > mylog.out 2>&1 &
- Python 安装第三方库,pip install 安装慢,安装不上的解决办法
今天来说一下,有些刚刚接触python的朋友,在使用pip install安装python 第三方库的过程中 会出现网速很慢,或者是安装下载到中途,停止,卡主,或者是下载报错等问题.如下图: 还有一些 ...