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. pycharm 秘籍:快捷键技巧等

    Pycharm基本使用 安装 下载地址:https://www.jetbrains.com/pycharm/download 选择Professional 专业版 Comunnity社区版是免费的,但 ...

  2. python编程学习路线及笔记

    话不多说,直接上图! 关于人工智能算法学习思路,欢迎浏览我的另一篇随笔:如果你想开始学习算法,不妨先了解人工智能有哪些方向? 之后博主将持续分享各大算法的学习思路和学习笔记:hello world: ...

  3. java web数据库的增删改查详细

    本次课上实验是完成数据库的增删改查. 包括增加用户信息.删除用户信息.多条件查找用户信息.修改用户信息(主要是复选框单选框等的相关操作.) 下面下看一下各个界面的样子. 总页面:显示全部页面:增加页面 ...

  4. Python设计模式(4)-装饰模式

    # coding=utf-8 # * 一般情况下,当一个基类写好之后,我们也许不愿意去改动,也不能改动,原因是# * 这样的在项目中用得比较久的基类,一旦改动,也许会影响其他功能模块,但是,# * 又 ...

  5. scala_spark实践4

    SparkStreaming中foreachRDD SparkStreaming是流式实时处理数据,就是将数据流按照定义的时间进行分割(就是“批处理”).每一个时间段内处理的都是一个RDD.而Spar ...

  6. xargs与exec区别

    平时使用find命令查找出文件的时候有时候后面有时候用-exec有时候用管道加xargs,这2个到底有什么不同?下面就这2个的不同做简单介绍. 零.实验环境 [root@osker /]# find ...

  7. Property [*****] not found on type [com.erp.pojo.ErpSupplier]

    我实体类里用的是 springboot 里@Slf4j   @Data  注解式写的  这样可以减少代码量 ,但是遇到一个问题影响我好长时间 出现了这个错误  Property [*****] not ...

  8. Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(四)之Operators

    At the lowest level, data in Java is manipulated using operators Using Java Operators An operator ta ...

  9. Daily Scrum 12/29/2015

    Process: Zhaoyang: Add the Time bar feature in the APP and complete the Speech API. Yandong: Do some ...

  10. ATcoder E - Flatten 质因子分解求LCM

    题解:其实就是求n个数的lcm,由于数据特别大,求lcm时只能用质因子分解的方法来求. 质因子分解求lcm.对n个数每个数都进行质因子分解,然后用一个数组记录某个质因子出现的最大次数.然后累乘pow( ...