Scala教程之:PartialFunction
Scala中有一个很有用的traits叫PartialFunction,我看了下别人的翻译叫做偏函数,但是我觉得部分函数更加确切。
那么PartialFunction是做什么用的呢?简单点说PartialFunction用在模式匹配中,是一个不完整的函数,它只实现了函数的部分功能,也就是列举了部分case的情况。
我们先看下PartialFunction的定义:
trait PartialFunction[-A, +B] extends (A => B) {
...
def isDefinedAt(x: A): Boolean
...
我们可以看到PartialFunction是一个trait,它继承自函数 (A => B), 这个函数有一个参数和一个返回值,在Scala中,该函数会被自动解析为Function1。
我们看下Function1的定义:
trait Function1[@specialized(scala.Int, scala.Long, scala.Float, scala.Double) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double) +R] extends AnyRef { self =>
/** Apply the body of this function to the argument.
* @return the result of function application.
*/
def apply(v1: T1): R
我们可以看到Function1定义了一个方法: def apply(v1: T1): R
PartialFunction也定义了一个方法: def isDefinedAt(x: A): Boolean
如果我们要自己实现一个PartialFunction,则必须实现上述两个方法:
val inc = new PartialFunction[Any, Int] {
override def isDefinedAt(x: Any): Boolean = ???
override def apply(v1: Any): Int = ???
}
其中isDefinedAt用来选择PartialFunction入参的范围,而apply是真正的业务逻辑。
除了用new来实例化一个PartialFunction外,还有一个最简单的方法就是使用case语句。 我们举个例子, 如果我们有段case逻辑是匹配各个好吃等级,如下:
println("Step 1: Review of Pattern Matching in Scala")
val donut = "Glazed Donut"
val tasteLevel = donut match {
case "Glazed Donut" | "Strawberry Donut" => "Very tasty"
case "Plain Donut" => "Tasty"
case _ => "Tasty"
}
println(s"Taste level of $donut = $tasteLevel")
我们使用了3个case语句,看起来比较繁琐,使用PartialFunction, 我们可以将其转换为如下的形式:
val donutTaste = isVeryTasty orElse isTasty orElse unknownTaste
println(donutTaste("Glazed Donut"))
println(donutTaste("Plain Donut"))
println(donutTaste("Chocolate Donut"))
PartialFunction可以通过使用orElse关键字来合并成一个完整的Function。
我们看下这几个PartialFunction该怎么定义:
val isVeryTasty: PartialFunction[String, String] = {
case "Glazed Donut" | "Strawberry Donut" => "Very Tasty"
}
val isTasty: PartialFunction[String, String] = {
case "Plain Donut" => "Tasty"
}
val unknownTaste: PartialFunction[String, String] = {
case donut1 @ _ => s"Unknown taste for donut = $donut1"
}
实际上就是把整个的业务逻辑,用PartialFunction拆分开来了。这里使用case语句,会自动转换成为PartialFunction。
关注下最后一个unknownTaste的case语句, @ 使用来做模式匹配的, case donut1 @ _ 就意味着 donut1 将会匹配所有的输入。
更多教程请参考 flydean的博客
Scala教程之:PartialFunction的更多相关文章
- Scala教程之:Future和Promise
文章目录 定义返回Future的方法 阻塞方式获取Future的值 非阻塞方式获取Future的值 Future链 flatmap VS map Future.sequence() VS Future ...
- scala教程之:可见性规则
文章目录 public Protected private scoped private 和 scoped protected 和java很类似,scala也有自己的可见性规则,不同的是scala只有 ...
- Scala教程之:深入理解协变和逆变
文章目录 函数的参数和返回值 可变类型的变异 在之前的文章中我们简单的介绍过scala中的协变和逆变,我们使用+ 来表示协变类型:使用-表示逆变类型:非转化类型不需要添加标记. 假如我们定义一个cla ...
- Scala教程之:Either
在之前的文章中我们提到了Option,scala中Option表示存在0或者1个元素,如果在处理异常的时候Option就会有很大的限制,因为Option如果返回None,那么我并不知道具体的异常到底是 ...
- Scala教程之:可变和不变集合
文章目录 mutable HashMap immutable HashMap 集合在程序中是非常有用的,只有用好集合才能真正感受到该语言的魅力.在scala中集合主要在三个包里面:scala.coll ...
- Scala教程之:Enumeration
Enumeration应该算是程序语言里面比较通用的一个类型,在scala中也存在这样的类型, 我们看下Enumeration的定义: abstract class Enumeration (init ...
- Scala教程之:Option-Some-None
文章目录 Option和Some Option和None Option和模式匹配 在java 8中,为了避免NullPointerException,引入了Option,在Scala中也有同样的用法. ...
- Scala教程之:scala的参数
文章目录 默认参数值 命名参数 scala的参数有两大特点: 默认参数值 命名参数 默认参数值 在Scala中,可以给参数提供默认值,这样在调用的时候可以忽略这些具有默认值的参数. def log(m ...
- Scala教程之:可扩展的scala
文章目录 隐式类 限制条件 字符串插值 s 字符串插值器 f 插值器 raw 插值器 自定义插值器 Scala是扩展的,Scala提供了一种独特的语言机制来实现这种功能: 隐式类: 允许给已有的类型添 ...
随机推荐
- dis反汇编查看实现
dis库是python(默认的CPython)自带的一个库,可以用来分析字节码 >>> import dis >>> def add(a, b = 0): ... ...
- 前端面试题解密:经典算法之冒泡算法(ES6版)及优化
前言 随着前端的飞速发展,前端业务开发给前端工程师提出了更高的要求,因而算法题也越来越高频次的出现在前端面试中.有很多的小伙伴找胡哥苦诉,在前端实际开发中(除了涉及游戏开发方面),算法使用有很多吗?大 ...
- python的字符串、列表、字典和函数
一.字符串 在python中字符串无需通过像php中的explode或者javascript中的split进行分解即可完成切片,可以直接通过下标获取字符串中的每一个字符,下标从0开始,如果从厚望签署, ...
- 【php】php操作MySQL数据库
一.操作步骤: 1. 连接MySQL数据库并判断是否连接成功2. 选择数据库3. 设置字符集4. 准备SQL语句5. 向MySQL服务发送SQL语句6. 解析处理结果集7. 释放结果集,关闭数据库连接 ...
- django、celery异步发邮件
django.celery异步发邮件 django自带的send_mail发邮件功能执行发邮件功能会因为网络的原因造成花费的时间过长,为了解决这个问题,可以用celery + redis代替 安装包: ...
- 路由与交换,cisco路由器配置,浮动静态路由
设置浮动静态路由的目的就是为了防止因为一条线路故障而引起网络故障.言外之意就是说浮动静态路由实际上是主干路由的备份.例如下图: 假如我们设路由器之间的串口(seria)为浮动静态路由(管理距离为100 ...
- 29.2 Iterator 迭代器
/* * 集合的遍历方式: * 1.toArray(),可以把集合转换成数组,然后遍历数组即可 * 2.iterator(),可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合 * * Iter ...
- dp优化---四边形不等式与决策单调性
四边形不等式 定理1: 设w(x,y)为定义在整数集合上的二元函数,若存在任意整数a,b,c,d(a<=b<=c<=d),并且w(a,d)+w(b,c)>=w(a,c)+w(b ...
- GO中的channel使用小结
go关键字可以用来开启一个goroutine(协程))进行任务处理,而多个任务之间如果需要通信,就需要用到channel了. func testSimple(){ intChan := make(ch ...
- 常见的 PHP 面试题和答案分享
如何直接将输出显示给浏览器? 将输出直接显示给浏览器,我们必须使用特殊标记 <?=and?>. PHP 是否支持多重继承? PHP 只支持单继承.PHP 的类使用关键字 extends 继 ...