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的更多相关文章

  1. Scala教程之:Future和Promise

    文章目录 定义返回Future的方法 阻塞方式获取Future的值 非阻塞方式获取Future的值 Future链 flatmap VS map Future.sequence() VS Future ...

  2. scala教程之:可见性规则

    文章目录 public Protected private scoped private 和 scoped protected 和java很类似,scala也有自己的可见性规则,不同的是scala只有 ...

  3. Scala教程之:深入理解协变和逆变

    文章目录 函数的参数和返回值 可变类型的变异 在之前的文章中我们简单的介绍过scala中的协变和逆变,我们使用+ 来表示协变类型:使用-表示逆变类型:非转化类型不需要添加标记. 假如我们定义一个cla ...

  4. Scala教程之:Either

    在之前的文章中我们提到了Option,scala中Option表示存在0或者1个元素,如果在处理异常的时候Option就会有很大的限制,因为Option如果返回None,那么我并不知道具体的异常到底是 ...

  5. Scala教程之:可变和不变集合

    文章目录 mutable HashMap immutable HashMap 集合在程序中是非常有用的,只有用好集合才能真正感受到该语言的魅力.在scala中集合主要在三个包里面:scala.coll ...

  6. Scala教程之:Enumeration

    Enumeration应该算是程序语言里面比较通用的一个类型,在scala中也存在这样的类型, 我们看下Enumeration的定义: abstract class Enumeration (init ...

  7. Scala教程之:Option-Some-None

    文章目录 Option和Some Option和None Option和模式匹配 在java 8中,为了避免NullPointerException,引入了Option,在Scala中也有同样的用法. ...

  8. Scala教程之:scala的参数

    文章目录 默认参数值 命名参数 scala的参数有两大特点: 默认参数值 命名参数 默认参数值 在Scala中,可以给参数提供默认值,这样在调用的时候可以忽略这些具有默认值的参数. def log(m ...

  9. Scala教程之:可扩展的scala

    文章目录 隐式类 限制条件 字符串插值 s 字符串插值器 f 插值器 raw 插值器 自定义插值器 Scala是扩展的,Scala提供了一种独特的语言机制来实现这种功能: 隐式类: 允许给已有的类型添 ...

随机推荐

  1. tensorflow编程学习路线及笔记

    话不多说,直接上图! 关于人工智能算法学习思路,欢迎浏览我的另一篇随笔:如果你想开始学习算法,不妨先了解人工智能有哪些方向? 关于python编程学习路线及笔记,欢迎浏览我的另一篇随笔:python编 ...

  2. 1054 The Dominant Color (20分)(水)

    Behind the scenes in the computer's memory, color is always talked about as a series of 24 bits of i ...

  3. Azure多因素认证

    什么是多重身份验证? 双重验证是需要多种验证方法的身份验证方法,可为用户登录和事务额外提供一层重要的安全保障. 它的工作原理是需要以下两种或多种验证方法: 用户知道的某样东西(通常为密码) 用户具有的 ...

  4. resetFields() 有时无效问题

    elementui在重置表单时,无法使用this.$refs['formRefVal'].resetFields()清空表单数据; elementui 设置rules后没有效果 解决方法: prop属 ...

  5. 【php】php操作MySQL数据库

    一.操作步骤: 1. 连接MySQL数据库并判断是否连接成功2. 选择数据库3. 设置字符集4. 准备SQL语句5. 向MySQL服务发送SQL语句6. 解析处理结果集7. 释放结果集,关闭数据库连接 ...

  6. Linux基础管理篇,软件管理程序,yum与rpm

    一.RPM 一般来说,rpm类型的文件在安装的时候,会检测当前的系统是否满足当前软件需要的环境.若符合,则该软件就会被安装,并且会把软件的相关信息写入/var/lib/rpm/目录下的数据库文件中. ...

  7. python 判断一个字符串是否是小数

    """练习判断一个小数1.判断是否合法2.合法需要有一个小数点3.小数点左边必须是个整数,右边必须是个正整数 """ def xiaoshu ...

  8. matplotlib IdentityTransform(原地变换)

    2020-04-12 23:33:56 -- Edit by yangrayIdentityTransform继承于Affine2DBase类,它是一个高效实现原地变换的类.(不知道有什么用,变换前后 ...

  9. 关于TOMCAT中的两个Web.xml

    关于TOMCAT中的两个Web.xml (2013-01-19 17:32:57) 转载▼ 标签: 杂谈   初学JAVA web开发.. Servlet定义的时候,我发现在${catalina.ho ...

  10. Java课程设计之——Web前端

    主要使用的技术 Javascript/JQuery html css Jsp 前期调查 能看到的网页大致可以分为两个部分,一个是搜索的首页index.html,一个是搜索结果页/s index.htm ...