用一个例子告诉你 Scala中函数、偏函数、偏应用函数的区别

1. 函数

函数是和其他编程语言定义类似的一种控制抽象结构

具体的使用 可以看这里 🌰


2. 偏应用函数

偏应用函数(Partially Applied Function),为了和偏函数做区分,最好翻译为 部分应用函数

部分应用函数是

        在函数调用时,如果存在部分未确定的参数,而制定的一种语法规则(部分应用函数表达式)

        它的本质是 scala包下FunctionX特质的一个实例

        同理,在 初始化对象时,也可以使用部分应用函数


示例:

    def sum(x: Int, y: Int) = x + y

    //第一个参数确定,第二个参数不确定
    val Pxsum: Int => Int = sum(10, _)

    //两个参数都不确定
    val Pxysum: (Int, Int) => Int = sum(_, _) // 标准格式
    val Pxysum2: (Int, Int) => Int = sum _ // 简写为 sum _
    val Pxysum3: (Int, Int) => Int = sum // 简写为 sum

    //作为Lambda表达式使用
    val list = List(1, 2, 3, 4)

    list.map(sum(10, _)).foreach(println)
    
    //初始化对象时,使用部分应用函数
    case class cPerson(id: Int, name: String, age: Int)

    val cp: Int => cPerson = cPerson(_, "大王", 20)

    val x: cPerson = cp(10)

原理:

        部分应用函数是scala编译器,根据部分应用表达式 sum(10,_) 或 cPerson(_,"大王",_)

        而创建的工厂类的实例

    def sum(x: Int, y: Int) = x + y

    //第一个参数确定,第二个参数不确定
    val Pxsum: Int => Int = sum(10, _)

    //调用部分应用函数
    Pxsum(10)
    Pxsum.apply(10)

    /*
    * 部分应用函数原理:
    *   1. Scala编译器根据 sum(10, _) 生成了一个新的函数类(Function1特质的实例)
    *   2. 这个 Function1类,实现了apply方法
    *       def apply(v1: T1): 原函数返回值类型 = {
    *             sum(10,v1)
    *       }
    * */

3. 偏函数

偏函数(partial function)是Scala中定义的一个特质,trait PartialFunction[-A, +B]

         A表示: 接收的参数类型

         B表示: 返回的结果类型

Scala中允许使用 { case分支 } 来初始化 PartialFunction实现类的实例

        不像普通函数那样只有一个参数列表,在偏函数中每个 case分支都有自己的参数列表和主体逻辑 

格式: 

        val 变量名称: PartialFunction[-A, +B]  = {

                case 分支

        }

        注意: 当 调用偏函数时,如果参数没在定义的函数域内,将会触发 scala.MatchError


3.1 初始化偏函数实例

必须显式声明变量为 PartialFunction[-A,+B] 类型 (编译器不会自动推断偏函数类型)

    //使用函数字面量初始化
    val pf: PartialFunction[Any, Unit] = {
      case s: String => println("case 1")
      case i: Int => println("case 2")
      // case _ => println("兜底逻辑")
    }

    pf("abc") // case 1
    pf(1) // case 2
    pf(1.7) // 当参数不在函数域时,会触发 scala.MatchError

    // 定义具多个参数的偏函数
    val pf: PartialFunction[(Int, Int), Int] = {
      case (x, y) if x * y > 0 => x * y
      case (x, y) if x * y < 0 => -(x * y)
      case _ => 0
    }

    println(pf(1, 2))
    println(pf(-1, 2))
    println(pf(0, 2))

3.3 使用偏函数的方法

isDefinedAt(参数) :

        接收一个参数变量,检查输入的参数 是否能被 case分支的模式匹配

                能命中模式返回true,否则返回false

        常用来做参数的合法性校验

    val pf: PartialFunction[Any, Unit] = {
      case s: String => println("case 1")
      case i: Int => println("case 2")
    }

    println(pf.isDefinedAt(1.1)) // false
    println(pf.isDefinedAt(1)) // true

orElse(偏函数) :

      接收一个偏函数,并将这个偏函数与调用偏函数的逻辑拼接起来(逻辑拼接),相当于取 多个偏函数 case分支的并集 (case分支顺序 从左到右拼接)  

    val pf1: PartialFunction[Int, String] = {
      case x: Int if x > 0 => "One"
    }

    val pf2: PartialFunction[Int, String] = {
      case x: Int if x > 0 => "Two"
    }

    val pf3: PartialFunction[String, String] = {
      case "0" => "Three"
    }

    println(pf1(10)) // One
    println(pf1.orElse(pf2)(10)) // One
    val pf4: PartialFunction[Int, String] = pf1.orElse(pf2).orElse({ case x: Int if x == 0 => "Three" })
    println(pf4(0)) // Three
    val pf5: PartialFunction[String with Int, String] = pf1.orElse(pf3)

andThen(偏函数) :

        将 第一个偏函数的结果,作为第二个函数的参数(函数的连续调用)   

        注意: 第一个偏函数的结果类型 必须和第二个函数的参数类型 一致 

    val pf1: PartialFunction[Int, String] = {
      case x: Int if x > 0 => "One"
    }
    
    val pf = pf1.andThen(
      { case "One" => 1
      case _ => 0
      }
    )
    println(pf(1)) // 1

applyOrElse(参数,偏函数) :

        可以接收两个参数,第一个参数为调用函数的参数

                当参数能匹配调用函数的模式时,则返回调用函数的结果

                当参数不能匹配调用函数的模式时,则将参数作用于回调函数           

    val pf2: PartialFunction[Int, String] = {
      case x: Int if x < 0 => "Two"
    }

    def pf3(x:Int):String =x match {
      case x: Int if x < 0 => "Two"
    }

    val pf1: PartialFunction[Int, String] = {
      case x: Int if x > 0 => "One"
    }

    println(pf1.applyOrElse(-1, pf2)) // Two
    println(pf1.applyOrElse(-1, pf3)) // Two

4. 总结

部分应用函数:

         针对现有函数,快速生成 工厂方法(Scala编译器帮助实现)

偏函数:

         模式匹配 和 函数定义的完美结合,并自动实现了 扩展方法(Scala编译器帮助实现)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值