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. 深入解读ES6系列(二)

    ES6函数 哈喽小伙伴们,爱说'废'话的Z又回来了,欢迎来到Super IT曾的博客时间,上一节说了es6的历史,变量,以及闭包,这一节我们继续我们知识的海洋,一起奋斗不秃头!不足的欢迎提问留言. 今 ...

  2. HashMap源码与相关面试题

    一.哈希表 哈希表是一种可以快速定位得数据结构.哈希表可以做到平均查找.插入.删除时间是O(1),当然这是指不发生Hash碰撞得情况.而哈希表最大得缺陷就是哈希值得碰撞(collision). Has ...

  3. PTA数据结构与算法题目集(中文) 7-10

    PTA数据结构与算法题目集(中文)  7-10 7-10 公路村村通 (30 分)   现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低 ...

  4. LinkedHashMap 与 HashMap 实现的区别

    阅读前最好对 HashMap 的内部实现方式有一定了解 LinkedHashMap 继承自 HashMap 主要重写了一个节点类 LinkedHashMap.Entry,并维护一个头结点和尾节点 以及 ...

  5. 【php】面向对象(四)

    知识点:ai一. a => abstract(抽象类) a) 抽象类的修饰符,修饰类和成员方法 b) 注意:被修饰的类不能被实例化,被修饰的方法不能有程序体 c) 如果某一个类使用abstrac ...

  6. Spring XML Bean 定义的加载和注册

    前言 本篇文章主要介绍 Spring IoC 容器怎么加载 bean 的定义元信息. 下图是一个大致的流程图: 第一次画图,画的有点烂.

  7. json格式的文件操作2

    1.字典转换为字符串(json.dumps) jsongeshi={"name":"yajuan","age":"10" ...

  8. YII基础二

    YII多表关联查询 ->select("{{%relation_detail}}.name") ->from("{{%user}}") ->l ...

  9. ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 以及 同步的集合类 Hashtable 和 Vector Collections.synchronizedMap 和 Collections.synchronizedList 区别缺点

    ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含 ...

  10. stand up meeting 12/7/2015

    part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云  ------------------    --  ---------------------  --- PDF Rea ...