`
zhangxiong0301
  • 浏览: 359657 次
社区版块
存档分类
最新评论

case语句和偏函数

 
阅读更多

Scala通过case语句提供了形式简单、功能强大的模式匹配功能。但是也许你不知道,Scala还具有一个与case语句相关的语言特性,那就是:在Scala中,被“{}”包含的一系列case语句可以被看成是一个函数字面量,它可以被用在任何普通的函数字面量适用的地方,例如被当做参数传递。 

Scala代码  收藏代码
  1. scala> val defaultValue:Option[Int] => Int = {  
  2. case  Some(x) => x  
  3. case None => 0                                }                                                                      
  4. scala> defaultValue(Some(5))                         
  5. res1: Int = 5                     


defaultValue是一个函数字面量,它的值是: 

Scala代码  收藏代码
  1. {  
  2.   case  Some(x) => x  
  3.   case None => 0                                 
  4. }                        


看懂了以上的代码,我们就不难理解在Scala的Actor中经常使用的react函数的语法形式: 

Scala代码  收藏代码
  1. react {  
  2. case (name: String, actor: Actor) => {  
  3.   actor ! getip(name)  
  4.   act()  
  5. }  
  6. case msg => {  
  7.   println("Unhandled message: "+ msg)  
  8.   act()  
  9. }  
  10. }  


react是一个函数,它接收一个函数字面量作为参数。至此我们都没有提到偏函数的概念。什么是偏函数?它与Case语句有什么关系? 

在Scala中,偏函数是具有类型PartialFunction[-A,+B]的一种函数。A是其接受的函数类型,B是其返回的结果类型。偏函数最大的特点就是它只接受和处理其参数定义域的一个子集,而对于这个子集之外的参数则抛出运行时异常。这与Case语句的特性非常契合,因为我们在使用case语句是,常常是匹配一组具体的模式,最后用“_”来代表剩余的模式。如果一一组case语句没有涵盖所有的情况,那么这组case语句就可以被看做是一个偏函数。 

case语句作为偏函数字面量: 

Scala代码  收藏代码
  1. val second:PartialFunction[List[Int],Int] = {  
  2.     case List(x::y::_) => y  
  3. }  


second函数的功能是返回一个List[Int]中的第二个值。case函数体只涵盖了当一个List的长度大于2的情况,而忽略Nil和长度为1的列表。 

Scala代码  收藏代码
  1. scala.MatchError: List(2)  
  2.         at $anonfun$1.apply(<console>:9)  
  3.         at $anonfun$1.apply(<console>:9)  
  4.         at .<init>(<console>:11)  
  5.         at .<clinit>(<console>)  
  6.         at RequestResult$.<init>(<console>:9)  
  7.         at RequestResult$.<clinit>(<console>)  
  8.         at RequestResult$scala_repl_result(<console>)  
  9.         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
  10.         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)  
  11.         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)  
  12.         at java.lang.reflect.Method.invoke(Method.java:597)  
  13.         at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$18.apply(Interpreter.scala:981)  
  14.         at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$18.apply(Interpreter.scala:981)  
  15.         at scala.util.contr...  
  16.   
  17. scala> second(1::2::Nil)  
  18. res8: Int = 2  


当我们试图传入一个不在偏函数的定义域范围内的参数时,抛出了异常。如果我们想在调用函数前先检查一个参数是否在定义域范围以避免抛出异常,那么可以使用偏函数的isDefinedAt方法。 

Scala代码  收藏代码
  1. scala> second.isDefinedAt(List(2,3,4))  
  2. res10: Boolean = true  


实际上,scala编译器把函数字面量: 

Scala代码  收藏代码
  1. {  
  2.     case List(x::y::_) => y  
  3. }  


编译成了如下的等价形式: 

Scala代码  收藏代码
  1. new PartialFunction[List[Int], Int] {  
  2. def apply(xs: List[Int]) = xs match {  
  3. case x :: y :: _ => y  
  4. }  
  5. def isDefinedAt(xs: List[Int]) = xs match {  
  6. case x :: y :: _ => true  
  7. case _ => false  
  8. }  
  9. }  


这种转换是一种编译期行为,我们必须把second显式的声明为PartialFunction类型,如果没有给second指定类型,那么scala编译器会把后面的一组case语句编译成Function1类型,即完整的函数。 

Tips:一组case语句要成为一个偏函数,那么它被赋予的变量必须被声明为PartionFunction[-A,+B] 

那么我们什么时候该使用偏函数?或者说偏函数给我们带来了什么好处?当我们确定我们的程序不会被传入不可处理的值时,我们就可以使用偏函数。这样万一程序被传入了不应该被传入的值,程序自动抛出异常,而不需要我们手工编写代码去抛出异常,减少了我们的代码量。

分享到:
评论

相关推荐

    oracle case语句的介绍

    CASE 语句可以分为两种类型:简单 CASE 语句和搜索 CASE 语句。 - **简单 CASE 语句**(Simple CASE Statement):这种形式的 CASE 语句通常用于比较表达式的值,并根据匹配情况返回特定的结果。 **语法结构**:...

    用函数指针替代Switch/Case语句的程序设计方法

    单片机程序中,当Switch/Case语句分支较多、处理代码较长、处理情况较为复杂时,逻辑修改和程序调试均存在一定的困难。针对该问题,本文给出了使用函数指针替代Switch/Case语句的实现思路以及相对应的代码模型,为...

    Oracle-Decode()函数和CASE语句的比较

    Oracle数据库中的`Decode()`函数和`CASE`语句都是用于条件判断和数据转换的重要工具,它们各有特点,适用场景也有所不同。以下是对这两个功能的详细比较。 首先,`Decode()`函数是一个简化的条件表达式,它允许你在...

    mysql存储过程之case语句用法实例详解

    MySQL中的CASE语句是SQL语言中的一个重要组成部分,它在存储过程和复杂查询中扮演着条件判断的角色,使得代码更加简洁易读。CASE语句提供了两种形式:简单CASE和可搜索CASE。 1. 简单CASE语句: 简单CASE语句主要...

    Delphi高级Case语句应用实例..rar

    本教程将深入探讨`case`语句在Delphi中的高级应用,结合实际示例来帮助理解其功能和用法。 首先,我们要明白`case`语句的基本结构。在Delphi中,`case`语句用于基于一个表达式的值来选择执行多个可能的代码分支之一...

    if嵌套与case语句.doc

    在Pascal编程语言中,`if`语句和`case`语句是两种重要的选择结构,用于实现条件分支。在本篇文章中,我们将详细探讨这两种语句及其在实际编程中的应用。 首先,让我们来理解`if`语句的嵌套。在`if`语句中,`then`或...

    基于C语言实现switch case语句(源码)

    使用switch case语句根据不同的成绩等级进行匹配和输出相应的评价。在这里,使用了case语句的多值匹配,例如'A'和'a'都会输出"Excellent!"。 如果用户输入的成绩等级不在'A'、'B'、'C'、'D'、'F'范围内,则执行...

    SQL中Case语句用法讨论_BJ

    ### SQL中的Case语句深入解析 在SQL查询语言中,`Case`语句是一个非常强大的功能,用于在查询中执行条件判断,它可以根据不同的条件返回不同的结果,这使得SQL能够处理更加复杂的数据筛选和转换需求。`Case`语句有...

    matlab的循环语句和常用函数解析.docx

    MATLAB 编程基础知识点总结 ...MATLAB 编程基础知识点涵盖了循环语句、条件语句、函数和矩阵操作、MATLAB 程序设计结构等方面,掌握这些知识点可以帮助用户更好地使用 MATLAB 进行科学计算、数据分析和可视化等工作。

    Visual Basic.NET语句与函数大全

    这本书会详细介绍各种类型的语句,包括控制流语句(如条件语句If...Then、选择语句Select Case、循环语句For...Next、While...End While等)、声明语句(如Dim用于定义变量)、赋值语句(将值分配给变量)以及异常...

    switch 语句与 case 语句一起使用,每个 case 对应一个可能的值.rar

    需要注意的是,`switch`语句并不是所有编程语言都支持,比如Python就没有直接的`switch`语句,但可以通过字典和函数映射实现类似的功能。 在实际编程中,合理地使用`switch`和`case`可以帮助我们构建清晰、可读性强...

    计算机二级C语言考点18switch-case语句.pdf

    通过上述知识点的详细解释,我们可以看出C语言中switch-case语句的强大和灵活,同时也需要注意它的陷阱,如忘记break可能导致的case穿透问题。在实际编程和考试中,灵活运用这些知识点可以帮助我们更准确地控制程序...

    详细解析 mysql 中的 case when 语句的使用

    - CASE语句可以根据一个表达式的值与一系列的比较值进行匹配,当找到匹配的值时,返回对应的值。 - 如果没有找到匹配的值,且存在ELSE子句,则返回ELSE子句中的值;若不存在ELSE子句,则返回NULL。 3. **应用场景...

    scala的偏函数

    偏函数被包在花括号内没有match的一组case语句是一个偏函数 偏函数是PartialFunction[A, B]的一个实例 A代表输入参数类型 B代表返回结果类型 示例一 示例说明 定义一个偏函数,根据以下方式返回 参考代码 // func1...

    二进制翻译中跳转表恢复case语句

    二进制代码中,索引跳转的例子展示了如何通过寄存器运算和比较来实现case语句。例如,从栈中读取索引变量,减去下界,然后与上界比较,如果在范围内,就使用索引乘以表项大小计算跳转表中的偏移,从而确定目标地址。...

    sql中case语句的用法浅谈

    简单Case函数和Case搜索函数。 代码如下:–简单Case函数 CASE sex  WHEN ‘1’ THEN ‘男’  WHEN ‘2’ THEN ‘女’ ELSE ‘其他’ END –Case搜索函数 CASE WHEN sex = ‘1’ THEN ‘男’  WHEN sex = ‘2’ ...

    增加了case和for语句的pl0编译器及有关测试文件

    这里可能有对`case`和`for`语句解析所需的数据结构和辅助函数的定义,比如枚举类型、符号表管理或者其他与控制流相关的数据结构。 `pl0.exe`是编译器的可执行文件,用户可以直接运行它来编译PL0源代码。通过观察...

    MATLAB中的switch-case判断语句与for循环语句.md

    在MATLAB编程环境中,`switch-case`语句和`for`循环是两个非常重要的控制流程结构,它们可以帮助程序员根据不同的条件执行特定的操作,以及重复执行一系列操作直到满足指定的条件。 - **switch-case**语句:此结构...

Global site tag (gtag.js) - Google Analytics